学习了profile bean之后,发现有的时候bean还是有根据环境来选择的余地的,那么假设我们希望某个bean只有当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后,才会创建某个bean。

在Spring 4之前,很难实现这种级别的条件化配置,但是Spring 4引入了一个新的@Conditional注解,它可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。

今天就来学习下 条件化的Bean。

创建方法是在方或者类上 添加一个@Conditional(xxx.class)  xxx.class表示一个逻辑性的内容,当满足需求的时候返回true这样一来这个@Bean就会被创建,反之就不创建

  1. @Bean
  2. @Conditional(XXX.class)

这样一来,跟profile还是有点相似的,但是比他要强大的多的多。。。我们看Profile源码,你会发现Profile也添加了@Conditional,代码如下:

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target({ElementType.TYPE, ElementType.METHOD})
  3. @Documented
  4. @Conditional({ProfileCondition.class})
  5. public @interface Profile {
  6. String[] value();
  7. }

这个时候在查看下ProfileCondition.class

  1. class ProfileCondition implements Condition {
  2. ProfileCondition() {
  3. }
  4. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  5. if(context.getEnvironment() != null) {
  6. MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
  7. if(attrs != null) {
  8. Iterator var4 = ((List)attrs.get("value")).iterator();
  9. Object value;
  10. do {
  11. if(!var4.hasNext()) {
  12. return false;
  13. }
  14. value = var4.next();
  15. } while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));
  16.  
  17. return true;
  18. }
  19. }
  20. return true;
  21. }
  22. }

这个时候我们会发现 有一个接口 Condition,之所以那么牛逼 估计全靠这个吧,看一下源码:

  1. public interface Condition {
  2. boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
  3. }

有了ConditionContext,我们可以做到如下几点:

  • 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;
  • 借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是
  • 否存在,甚至探查bean的属性;
  • 借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是
  • 什么;
  • 读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;
  • 借助getClassLoader()返回的ClassLoader加载并检查类是否存在。

有了AnnotatedTypeMetadata则能够让我们检查带有@Bean注解的方法上还有什么其他的注解。

下面就以例子来说明:

假设有两个赏金猎人,一个高级的,一个初级的,他们各种会根据各自的赏金面板的消息(即Condition接口的实现类),决定是否去开始猎杀目标,下面先创造猎人接口以及两个猎人

  1. public interface BountyHunter {
  2.  
  3. void BeginHuntAndKill();
  4. }

高级赏金猎人

  1. public class SeniorBountyHunter implements BountyHunter {
  2.  
  3. public void BeginHuntAndKill() {
  4. System.out.println("我是高级赏金猎人哇哈哈哈,现在已有任务发布,我可以去做任务了!");
  5. }
  6. }

初级赏金猎人

  1. public class PrimaryBountyHunter implements BountyHunter {
  2.  
  3. public void BeginHuntAndKill() {
  4. System.out.println("我是初级赏金猎人乌卡卡卡,现在已有任务发布,我可以去做任务了!");
  5. }
  6. }

然后分别再创建 各自的任务面板

高级任务

  1. public class SeniorBounty implements Condition {
  2.  
  3. public boolean matches(ConditionContext conditionContext,
  4. AnnotatedTypeMetadata annotatedTypeMetadata) {
  5. /**
  6. * 各种自己想要的验证,然后根据结果来返回 一个boole值
  7. */
  8. if (conditionContext.getEnvironment().acceptsProfiles("task")) {
  9. return true;
  10. } else {
  11. return false;
  12. }
  13. }
  14. }

初级任务

  1. public class PrimaryBounty implements Condition {
  2.  
  3. public boolean matches(ConditionContext conditionContext,
  4. AnnotatedTypeMetadata annotatedTypeMetadata) {
  5. /**
  6. * 各种自己想要的验证,然后根据结果来返回 一个boole值
  7. */
  8.  
  9. if (conditionContext.getEnvironment().acceptsProfiles("task")) {
  10. return true;
  11. } else {
  12. return false;
  13. }
  14. }
  15. }

任务有了,人物也有了,下面就是需要一个人大喊一下:有新的任务发布了,赶紧去看啊!!

也就是Bean配置类

  1. @Configuration
  2. public class TaskConfig {
  3.  
  4. @Bean
  5. @Conditional(PrimaryBounty.class)
  6. public BountyHunter ThePrimaryBountyHunter() {
  7. return new PrimaryBountyHunter();
  8. }
  9.  
  10. @Bean
  11. @Conditional(SeniorBounty.class)
  12. public BountyHunter TheSeniorBountyHunter() {
  13. return new SeniorBountyHunter();
  14. }
  15. }

现在有人通知了,让我们看一下是否有人领任务,开始去猎杀!

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes = TaskConfig.class)
  3. @ActiveProfiles("task")
  4. public class TaskBegin {
  5.  
  6. @Autowired
  7. SeniorBountyHunter seniorBountyHunter;
  8.  
  9. @Autowired
  10. PrimaryBountyHunter primaryBountyHunter;
  11.  
  12. @Test
  13. public void TaskLog() {
  14. if (primaryBountyHunter != null) {
  15. primaryBountyHunter.BeginHuntAndKill();
  16. }
  17. if (seniorBountyHunter != null) {
  18. seniorBountyHunter.BeginHuntAndKill();
  19. }
  20. }
  21. }

这边我们是根据Profile来测试的,根据这个判断任务是否满足,当然我们也可以不根据配置环境,我们可以根据任务的的属性是否跟猎人相匹配(即 可以根据 @Conditional(xxx.class) xxx.class 类中的判断,该Bean是否有我们需要的属性 )

测试结果

以上就是条件化的bean配置 简单小例子,如有错误,请指出,谢谢~

代码:https://github.com/eoooxy/springinaction test下 的com.bean.condition中

SpringInAction--条件化的Bean的更多相关文章

  1. 第3章—高级装配—条件化的Bean

    条件化的Bean 通过活动的profile,我们可以获得不同的Bean.Spring 4提供了一个更通用的基于条件的Bean的创建方式,即使用@Conditional注解. @Conditional根 ...

  2. 002Conditional条件化创建bean

    01.条件化配置bean @Bean @Conditional(MagicExistsCondition.class)---->条件化创建bean public MagicBean magicB ...

  3. Spring入门(六):条件化的bean

    1. 概念 默认情况下,Spring中定义的bean在应用程序启动时会全部装配,不管当前运行的是哪个环境(Dev,QA或者Prod),也不管当前运行的是什么系统(Windows或者Linux),但有些 ...

  4. (二)spring 高级装配-Condition -条件化的bean

    Condition:满足某个特定条件的情况下创建bean 条件化配置bean: a:@Conditional 指定一个class ,它指明了通过条件对比的类.如果没有指定class则通过Condito ...

  5. Spring 梳理-profile与条件化定义bean

    定义profile <beans> //root <beans profile="dev"> <bean id=.../> </beans ...

  6. 【Java Web开发学习】Spring4条件化的bean

    [Java Web开发学习]Spring4条件化的bean 转载:https://www.cnblogs.com/yangchongxing/p/9071960.html Spring4引入了@Con ...

  7. Spring高级装配(二) 条件化的bean

    如果你希望一个bean在特定的条件下才会出现: 应用的类路径下包含特定的库时才创建 只有当某个特定的bean也声明之后才会创建 某个特定的环境变量设定之后才创建某个bean 在Spring 4之前,很 ...

  8. 001profile条件化创建bean

    01.类级别条件创建 @Configuration @Profile("dev") public class Aclass{}---->影响整个类,包括类的注解.开发环境,类 ...

  9. @Condition 条件化注册Bean

    看<Spring源码深度解析>笔记 1.@Condition: 按照一定的条件进行判断,满足条件给容器中注册bean:实例: 根据系统给容器中注册Bean,如果是windows注册(“bi ...

  10. spring对bean的高级装配之基于@Conditional条件化装配

    上篇介绍了如何基于profile来条件化创建bean,spring会根据profile的激活状态来进行创建;这篇介绍如何基于spring4.0引入的@Conditional和Condition接口来更 ...

随机推荐

  1. Java RSA公钥加密,私钥解密算法的尝试

    https://www.cnblogs.com/liemng/p/6699257.html 写这篇博客其实是有点意外的,来源最初也算是入职当前这家公司算吧,由于项目要求数据几乎都进行了加密(政府项目么 ...

  2. python3_pickle模块详解

    python3 pickle持久化的储存数据. python程序运行中得到了一些字符串,列表,字典等数据,想要长久的保存下来,方便以后使用,而不是简单的放入内存中关机断电就丢失数据.python模块大 ...

  3. 自制mysql的rpm包

    MySQL安装一般使用RPM或者源码安装的方式.RPM安装的优点是快速,方便.缺点是不能自定义安装目录.如果需要调整数据文件和日志文件的存放位置,还需要进行一些手动调整.源码安装的优点是可以自定义安装 ...

  4. awk循环语句-【AWK学习之旅】

      AWK中两种循环语句:if-else 和 while   控制流语句: 1.if-else 求总数,平均值: [root@monitor awkdir]# awk '$3>6 {n = n ...

  5. center os7.2 apache+php+mysql环境配置并设置https访问

    本人阿里云购买的center os7.2系统,小程序只支持https,因此需要配置https 安装apache yum -y install httpd systemctl start httpd a ...

  6. MR案例:单表关联查询

    "单表关联"这个实例要求从给出的数据中寻找所关心的数据,它是对原始数据所包含信息的挖掘. 需求:实例中给出 child-parent(孩子—父母)表,要求输出 grandchild ...

  7. v4l2的学习建议和流程解析

    v4l2,一开始听到这个名词的时候,以为又是一个很难很难的模块,涉及到视频的处理,后来在网上各种找资料后,才发现其实v4l2已经分装好了驱动程序,只要我们根据需要调用相应的接口和函数,从而实现视频的获 ...

  8. POJ_2182 Lost Cows(线段树的简单应用)

    基本思路就是,从后往前读取数字small[i].在剩余编号集合里(一开始剩余编号集合为全集)查找第small[i]+1个编号,该编号就是对应位置牛的编号. 若直接用数组来做,则每次查找都需要遍历前n个 ...

  9. [转]常见HTTP状态(如200,304,404,503)

    在网站建设的实际应用中,容易出现很多小小的失误,就像mysql当初优化不到位,影响整体网站的浏览效果一样,其实,网站的常规http状态码的表现也是一样,Google无法验证网站几种解决办法,提及到由于 ...

  10. WinCE数据通讯之Web Service分包传输篇

    前面写过<WinCE数据通讯之Web Service篇>那篇对于数据量不是很大的情况下单包传输是可以了,但是对于大数据量的情况下WinCE终端的内存往往会在解包或者接受数据时产生内存溢出. ...