zoukankan      html  css  js  c++  java
  • SpringInAction--条件化的Bean

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

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

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

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

     @Bean
     @Conditional(XXX.class)

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

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Documented
    @Conditional({ProfileCondition.class})
    public @interface Profile {
        String[] value();
    }

    这个时候在查看下ProfileCondition.class

    class ProfileCondition implements Condition {
        ProfileCondition() {
        }
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            if(context.getEnvironment() != null) {
                MultiValueMap attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
                if(attrs != null) {
                    Iterator var4 = ((List)attrs.get("value")).iterator();
                    Object value;
                    do {
                        if(!var4.hasNext()) {
                            return false;
                        }
                        value = var4.next();
                    } while(!context.getEnvironment().acceptsProfiles((String[])((String[])value)));
    
                    return true;
                }
            }
            return true;
        }
    }

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

    public interface Condition {
        boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
    }

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

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

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

    下面就以例子来说明:

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

    public interface BountyHunter {
    
        void BeginHuntAndKill();
    }

    高级赏金猎人

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

    初级赏金猎人

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

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

    高级任务

    public class SeniorBounty implements Condition {
    
    
        public boolean matches(ConditionContext conditionContext,
                               AnnotatedTypeMetadata annotatedTypeMetadata) {
            /**
             * 各种自己想要的验证,然后根据结果来返回 一个boole值
             */
            if (conditionContext.getEnvironment().acceptsProfiles("task")) {
                return true;
            } else {
                return false;
            }
        }
    }

    初级任务

    public class PrimaryBounty implements Condition {
    
        public boolean matches(ConditionContext conditionContext,
                               AnnotatedTypeMetadata annotatedTypeMetadata) {
            /**
             * 各种自己想要的验证,然后根据结果来返回 一个boole值
             */
    
            if (conditionContext.getEnvironment().acceptsProfiles("task")) {
                return true;
            } else {
                return false;
            }
        }
    }

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

    也就是Bean配置类

    @Configuration
    public class TaskConfig {
    
        @Bean
        @Conditional(PrimaryBounty.class)
        public BountyHunter ThePrimaryBountyHunter() {
            return new PrimaryBountyHunter();
        }
    
        @Bean
        @Conditional(SeniorBounty.class)
        public BountyHunter TheSeniorBountyHunter() {
            return new SeniorBountyHunter();
        }
    }

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

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = TaskConfig.class)
    @ActiveProfiles("task")
    public class TaskBegin {
    
        @Autowired
        SeniorBountyHunter seniorBountyHunter;
    
        @Autowired
        PrimaryBountyHunter primaryBountyHunter;
    
        @Test
        public void TaskLog() {
            if (primaryBountyHunter != null) {
                primaryBountyHunter.BeginHuntAndKill();
            }
            if (seniorBountyHunter != null) {
                seniorBountyHunter.BeginHuntAndKill();
            }
        }
    }

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

    测试结果

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

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

  • 相关阅读:
    css hack 【转】http://blog.csdn.net/arcow/article/details/1681027
    插入错误: 列名或所提供值的数目与表定义不匹配。
    XCopy 过程加日志
    textindent br
    asp.net 防止重复提交
    穷在闹市无人问,富在深山有远亲
    关于SqlDataReader遍历和缓存结果集
    在AJAX中使用 JS
    Application、Session和Cookie 的区别 总结
    C#中抽象类和接口的区别与使用
  • 原文地址:https://www.cnblogs.com/eoooxy/p/6432329.html
Copyright © 2011-2022 走看看