• spring源码 - @Condition原理及运用


    1.在源码中,在生成beanfinition中有有如一段代码

    以下代码逻辑中执行this.conditionEvaluator.shouldSkip返回true直接跳出beandefinition生成逻辑

    1. private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
    2. @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
    3. @Nullable BeanDefinitionCustomizer[] customizers) {
    4. AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
    5. if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    6. return;
    7. }
    8. abd.setInstanceSupplier(supplier);
    9. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    10. abd.setScope(scopeMetadata.getScopeName());
    11. String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    12. AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    13. if (qualifiers != null) {
    14. for (Class<? extends Annotation> qualifier : qualifiers) {
    15. if (Primary.class == qualifier) {
    16. abd.setPrimary(true);
    17. }
    18. else if (Lazy.class == qualifier) {
    19. abd.setLazyInit(true);
    20. }
    21. else {
    22. abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    23. }
    24. }
    25. }
    26. if (customizers != null) {
    27. for (BeanDefinitionCustomizer customizer : customizers) {
    28. customizer.customize(abd);
    29. }
    30. }
    31. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    32. definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    33. BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    34. }

    2.查看shouldSkip代码逻辑

    1). 检查class中是否有@Condition注解,没有直接return fase

    2). 命出@Condition里内容,直接调用其matches方法,不满足返回true 

    1. public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
    2. if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
    3. return false;
    4. }
    5. if (phase == null) {
    6. if (metadata instanceof AnnotationMetadata &&
    7. ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
    8. return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
    9. }
    10. return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    11. }
    12. List<Condition> conditions = new ArrayList<>();
    13. for (String[] conditionClasses : getConditionClasses(metadata)) {
    14. for (String conditionClass : conditionClasses) {
    15. Condition condition = getCondition(conditionClass, this.context.getClassLoader());
    16. conditions.add(condition);
    17. }
    18. }
    19. AnnotationAwareOrderComparator.sort(conditions);
    20. for (Condition condition : conditions) {
    21. ConfigurationPhase requiredPhase = null;
    22. if (condition instanceof ConfigurationCondition) {
    23. requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
    24. }
    25. if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
    26. return true;
    27. }
    28. }
    29. return false;
    30. }

    3.从1和2我们可以得到结论

    关键在于@Condtion注解中内容的matches方法如果满足才可以继续生成bean

    4.@Condition注解代码 

    1. @Target({ElementType.TYPE, ElementType.METHOD})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. public @interface Conditional {
    5. /**
    6. * All {@link Condition} classes that must {@linkplain Condition#matches match}
    7. * in order for the component to be registered.
    8. */
    9. Class[] value();
    10. }

    从以下代码可以@Condition中内容其实就是Condition接口实现

    public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); }

    5.运用

    比如我们在生成类的beandefinition时查看类上有没有@EnableMyImportClass 注解, 

    1. @Target(ElementType.TYPE)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Import(MyDeferredImportSelector.class)
    4. public @interface EnableMyImportClass {
    5. String[] value();
    6. }

    没有不让其生成,我们自定义的MyCondition类如下:

    1. public class MyCondition implements Condition {
    2. @Override
    3. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    4. MergedAnnotations mergedAnnotations= metadata.getAnnotations();
    5. return mergedAnnotations.isDirectlyPresent(EnableMyImportClass.class);
    6. }
    7. }

    然后在某个类加上这样注解来测试

    @Configuration

    @PropertySource(value = "classpath:aa.properties")

    @EnableMyImportClass({"testme"})

    @Conditional(MyCondition.class)

    public class AppConfig {

    如果我们这里将注解EnableMyImportClass去掉,测试后会发现AppConfig的beandefintion根据就没有生成,如下

     如果没有去掉正常情况如下:

    6结论

    从以上的内容可以看出@Condition一个非常实用的注解,可以根据需求在做一些非常定制化的产品加载bean的逻辑,比如在有消息中间件产品中,可以根据系统参数据来判断是否启用对应MQ bean.

  • 相关阅读:
    CDN(Content Delivery Network)内容分发网络原理、组成、访问过程、动静态加速、作用详解
    Myeclipse的安装教程
    oCPC实践录 | oCPC转化的设计、选择、归因与成本设置(3)
    关于android:Retrofit-@Body参数不能与表单或多部分编码一起使用
    外汇天眼;VT Markets 赞助玛莎拉蒂MSG Racing电动方程式世界锦标赛
    ROS之话题通信
    Error: [mobx-miniprogram] no store specified (小程序全局数据共享bug)
    ikun必学!python 画一个简单的只因
    影响工业产品设计的主要因素
    重磅发布|腾讯云容器安全服务网络隔离功能已上线
  • 原文地址:https://blog.csdn.net/lin000_0/article/details/128004786