@ConditionalOnBean在方法上失效

@ConditionalOnBean在方法上失效

在自定义一个日志切面,作为一个工具提供给其它的模块依赖时,发现@ConditionalBean写在方法上失效了,却写在类上注入成功的问题。于是通过源码打断点,发现@ConditionalOnBean在方法上时,对自定义的bean无效且会导致bean注入失败。

//@ConditionalOnBean(annotation = {EnableAutoPintLog.class}) 此处生效
public class LogAutoConfiguration {

    @Bean
    @ConditionalOnBean(annotation = {EnableAutoPintLog.class}) //此处会失败
    public LogAspect logAspect() {
        return new LogAspect();
    }
}

首先全局搜索ConfigurationClassPostProcessor类,找到下面的postProcessBeanDefinitionRegistry入口,在下图所示。
在这里插入图片描述
再断点进行,在this.reader.loadBeanDefinitions(configClasses)打上断点
在这里插入图片描述
断点再到如下图所示
在这里插入图片描述
在断点处加上判断表达式configClass.getMetadata().getClassName().equals("com.zh.common.util.config.LogAutoConfiguration"),让停在指定的bean,并进入该方法。由于bean写在方法上,所以loadBeanDefinitionsForBeanMethod(beanMethod)处打上断点
在这里插入图片描述
进去,到this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)
在这里插入图片描述
shouldSkip方法中,判断该bean是否带有注解@ConditionalOnBean,当方法带有才会进入下面的condition.match逻辑。

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

        ... 省略代码
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

进入matchs方法,再进入getMatchOutcome方法

	@Override
	public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		String classOrMethodName = getClassOrMethodName(metadata);
		try {
		// 此处进入
			ConditionOutcome outcome = getMatchOutcome(context, metadata);
	@Override
	public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
		ConditionMessage matchMessage = ConditionMessage.empty();
		MergedAnnotations annotations = metadata.getAnnotations();
		if (annotations.isPresent(ConditionalOnBean.class)) {
		// 初始化,重要
			Spec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);
			// 自定义bean时候,会找不到对应的type而导致match失败
			MatchResult matchResult = getMatchingBeans(context, spec);
			if (!matchResult.isAllMatched()) {
				String reason = createOnBeanNoMatchReason(matchResult);
				return ConditionOutcome.noMatch(spec.message().because(reason));
			}
			matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
					matchResult.getNamesOfAllMatches());
		}

!!!此处重要,进入new spec构造方法里面,在deducedBeanType处推断bean的类型并赋值给type。以至后面的由于自定义bean找不到type,而判断类型出错
在这里插入图片描述
先判断是不是通过@bean在方法上注入的bean,是的话推断它的类型type并返回赋值,此时会导致后面因为这里不为空且找不到指定的type而match不成功。
当在类上添加注解@ConditionalOnBean上时候,由于不满足条件,返回空集。而不会导致type找不到问题。

		private Set<String> deducedBeanType(ConditionContext context, AnnotatedTypeMetadata metadata) {
			if (metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName())) {
				return deducedBeanTypeForBeanMethod(context, (MethodMetadata) metadata);
			}
			return Collections.emptySet();
		}

由于是自定义的bean,最终匹配不成功,忽略不处理,注入失败。
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值