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中

  • 相关阅读:
    dotnet 新项目格式与对应框架预定义的宏
    dotnet 线程静态字段
    dotnet 线程静态字段
    dotnet 通过 WMI 拿到显卡信息
    dotnet 通过 WMI 拿到显卡信息
    dotnet 通过 WMI 获取指定进程的输入命令行
    dotnet 通过 WMI 获取指定进程的输入命令行
    dotnet 通过 WMI 获取系统信息
    dotnet 通过 WMI 获取系统信息
    PHP show_source() 函数
  • 原文地址:https://www.cnblogs.com/eoooxy/p/6432329.html
Copyright © 2011-2022 走看看