spring源码 - @Conditional原理及运用

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

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

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
      @Nullable BeanDefinitionCustomizer[] customizers) {

   AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
   if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
   }
   abd.setInstanceSupplier(supplier);   
   ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
   abd.setScope(scopeMetadata.getScopeName());
   String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

   AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
   if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
         if (Primary.class == qualifier) {
            abd.setPrimary(true);
         }
         else if (Lazy.class == qualifier) {
            abd.setLazyInit(true);
         }
         else {
            abd.addQualifier(new AutowireCandidateQualifier(qualifier));
         }
      }
   }
   if (customizers != null) {
      for (BeanDefinitionCustomizer customizer : customizers) {
         customizer.customize(abd);
      }
   }

   BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
   definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

2.查看shouldSkip代码逻辑

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

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

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
   if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
      return false;
   }

   if (phase == null) {
      if (metadata instanceof AnnotationMetadata &&
            ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
         return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
      }
      return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
   }

   List<Condition> conditions = new ArrayList<>();
   for (String[] conditionClasses : getConditionClasses(metadata)) {
      for (String conditionClass : conditionClasses) {
         Condition condition = getCondition(conditionClass, this.context.getClassLoader());
         conditions.add(condition);
      }
   }

   AnnotationAwareOrderComparator.sort(conditions);

   for (Condition condition : conditions) {
      ConfigurationPhase requiredPhase = null;
      if (condition instanceof ConfigurationCondition) {
         requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
      }
      if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
         return true;
      }
   }

   return false;
}

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

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

4.@Condition注解代码 

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

   /**
    * All {@link Condition} classes that must {@linkplain Condition#matches match}
    * in order for the component to be registered.
    */
   Class<? extends Condition>[] value();

}

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

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

5.运用

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyDeferredImportSelector.class)
public @interface EnableMyImportClass {
   String[]  value();
}

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

public class MyCondition implements Condition {
   @Override
   public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
      MergedAnnotations mergedAnnotations= metadata.getAnnotations();
      return mergedAnnotations.isDirectlyPresent(EnableMyImportClass.class);
   }
}

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

@Configuration

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

@EnableMyImportClass({"testme"})

@Conditional(MyCondition.class)

public class AppConfig {

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

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

6结论

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值