ConditionalOnBean条件只有注解时永远不成立

   今天在使用@ConditionalOnBean注解的时候,条件只有一个自定义注解,一直无法匹配成功,然后开始调试查看问题出现在哪儿,最终得到结果,@ConditionalOnBean在使用条件只有注解的时候,必须要指定type或者name才可以,所以最终我写了个必然会成功的types将问题解决,

/**
 * 启用XXX.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface EnableXXX {

}



/**
 * 基础配置.
 */
@Configuration
public class XXXConfig {

   
    // 设定type为XXXConfig,这样条件会永远成立,问题解决
    @Bean
    @ConditionalOnBean(type = "XXXConfig ", annotation = EnableXXX.class)
    public LoggerConfiguration loggerConfiguration() {
        return new LoggerConfiguration();
    }
}

@SpringBootApplication
@EnableXXX 
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

下列代码为找原因的过程

// 下列代码是我当时遇到问题的代码的大致结构
/**
 * 启用XXX.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface EnableXXX {

}



/**
 * 基础配置.
 */
@Configuration
public class XXXConfig {

   
    @Bean
    @ConditionalOnBean(annotation = EnableXXX.class)
    public LoggerConfiguration loggerConfiguration() {
        return new LoggerConfiguration();
    }
}

@SpringBootApplication
@EnableXXX 
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

// 下列代码为找原因的过程
// 在OnBeanCondition类的getMatchOutcome有这么一段代码
if (metadata.isAnnotated(ConditionalOnBean.class.getName())) {
    // 在此处会去实例化BeanSearchSpec,我们去看看实例化代码
    BeanSearchSpec spec = new BeanSearchSpec(context, metadata, ConditionalOnBean.class);
    MatchResult matchResult = getMatchingBeans(context, spec);
    if (!matchResult.isAllMatched()) {
        String reason = createOnBeanNoMatchReason(matchResult);
        return ConditionOutcome.noMatch(ConditionMessage
                .forCondition(ConditionalOnBean.class, spec).because(reason));
    }
    matchMessage = matchMessage.andCondition(ConditionalOnBean.class, spec)
            .found("bean", "beans")
            .items(Style.QUOTE, matchResult.getNamesOfAllMatches());
}

// 调用此构造进行实例化
public BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata,
				Class<?> annotationType) {
    // 调用此构造进行实例化
    this(context, metadata, annotationType, null);
}

// 最终的构造方法
public BeanSearchSpec(ConditionContext context, AnnotatedTypeMetadata metadata,
        Class<?> annotationType, Class<?> genericContainer) {
    this.annotationType = annotationType;
    MultiValueMap<String, Object> attributes = metadata
            .getAllAnnotationAttributes(annotationType.getName(), true);
    collect(attributes, "name", this.names);
    collect(attributes, "value", this.types);
    collect(attributes, "type", this.types);
    collect(attributes, "annotation", this.annotations);
    collect(attributes, "ignored", this.ignoredTypes);
    collect(attributes, "ignoredType", this.ignoredTypes);
    collect(attributes, "parameterizedContainer", this.parameterizedContainers);
    this.strategy = (SearchStrategy) attributes.getFirst("search");
    BeanTypeDeductionException deductionException = null;
    try {
        // 在这个地方,我们可以知道,我并没有设定types和names,那么spring会很贴心当帮我做个类型推断
        if (this.types.isEmpty() && this.names.isEmpty()) {
            addDeducedBeanType(context, metadata, this.types);
        }
    }
    catch (BeanTypeDeductionException ex) {
        deductionException = ex;
    }
    validate(deductionException);
}

// 开始帮我做类型推断,调用addDeducedBeanTypeForBeanMethod方法
private void addDeducedBeanType(ConditionContext context, AnnotatedTypeMetadata metadata, final List<String> beanTypes) {
    if (metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName())) {
        addDeducedBeanTypeForBeanMethod(context, (MethodMetadata) metadata, beanTypes);
    }
}

private void addDeducedBeanTypeForBeanMethod(ConditionContext context,
				MethodMetadata metadata, final List<String> beanTypes) {
    try {
        // 在此处将我的方法的返回值设定上去,导致我的beanTypes变为了我方法的返回值
        // 这个时候types就会变为我的返回值也就是LoggerConfiguration,好的 我们继续往下看
        Class<?> returnType = getReturnType(context, metadata);
        beanTypes.add(returnType.getName());
    }
    catch (Throwable ex) {
        throw new BeanTypeDeductionException(metadata.getDeclaringClassName(),
                metadata.getMethodName(), ex);
    }
}

// 开始做匹配判断
protected final MatchResult getMatchingBeans(ConditionContext context,
			BeanSearchSpec beans) {
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    if (beans.getStrategy() == SearchStrategy.ANCESTORS) {
        BeanFactory parent = beanFactory.getParentBeanFactory();
        Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
                "Unable to use SearchStrategy.PARENTS");
        beanFactory = (ConfigurableListableBeanFactory) parent;
    }
    MatchResult matchResult = new MatchResult();
    boolean considerHierarchy = beans.getStrategy() != SearchStrategy.CURRENT;
    TypeExtractor typeExtractor = beans.getTypeExtractor(context.getClassLoader());
    List<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(
            beans.getIgnoredTypes(), typeExtractor, beanFactory, context,
            considerHierarchy);
    // 在上面我们得知,types当前为我的方法返回值 也就是LoggerConfiguration
    // 这个时候我想创建LoggerConfiguration,但是呢,条件为LoggerConfiguration必须在Bean工厂中存在
    // 所以就导致我无法成功创建出来LoggerConfiguration
    for (String type : beans.getTypes()) {
        Collection<String> typeMatches = getBeanNamesForType(beanFactory, type,
                typeExtractor, context.getClassLoader(), considerHierarchy);
        typeMatches.removeAll(beansIgnoredByType);
        if (typeMatches.isEmpty()) {
            matchResult.recordUnmatchedType(type);
        }
        else {
            matchResult.recordMatchedType(type, typeMatches);
        }
    }
    for (String annotation : beans.getAnnotations()) {
        List<String> annotationMatches = Arrays
                .asList(getBeanNamesForAnnotation(beanFactory, annotation,
                        context.getClassLoader(), considerHierarchy));
        annotationMatches.removeAll(beansIgnoredByType);
        if (annotationMatches.isEmpty()) {
            matchResult.recordUnmatchedAnnotation(annotation);
        }
        else {
            matchResult.recordMatchedAnnotation(annotation, annotationMatches);
        }
    }
    for (String beanName : beans.getNames()) {
        if (!beansIgnoredByType.contains(beanName)
                && containsBean(beanFactory, beanName, considerHierarchy)) {
            matchResult.recordMatchedName(beanName);
        }
        else {
            matchResult.recordUnmatchedName(beanName);
        }
    }
    return matchResult;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Listen丶Me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值