代码编织梦想

@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,最终匹配不成功,忽略不处理,注入失败。
在这里插入图片描述在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_45543606/article/details/129666978

spring boot 中 @conditionalonmissingbean和@conditionalonbean注解注意事项_weixin_33790053的博客-爱代码爱编程

2019独角兽企业重金招聘Python工程师标准>>> 关于使用@Bean注解注入bean导致ConditionOnMissBean和 ConditionOnBean 注解有时候会失效的问题 文档上提示,需要注意bean添加的顺序,因为该条件是根据当前加载

springboot自定义自动装配与conditional失效问题_static_lin的博客-爱代码爱编程

文章目录 前言自动装配规则类命名规则package命名规则jar包构建规则jar包结构jar包取名 构建自定义的自动装配@ConditionOnBean失效问题为何非自动装配的配置会失效?为何自动装配的配置

conditionalonmissingbean失效问题追踪_伊布拉西莫的博客-爱代码爱编程_conditionalonmissingbean不生效

遇到一个@ConditionalOnMissingBean失效的问题,今天花点时间来分析一下。 现场回放 services 首先介绍下代码结构:有RunService,以及它的两个实现类:TrainRunService

spring @Conditional 源码解析 以及@ConditionalOnMissingBean 失效之谜-爱代码爱编程

作者 | 曹恒源 为了防止这个世界被破坏,为了保护世界的和平,贯彻爱与真实的邪恶,可爱又迷人的程序员。 1 .前言 本文基于 spring-boot 2.2.2.RELEASE 版本,如果因版本变动导致实际细节和本文不符,概不负责。 @Conditional 注解在 spring-boot 中大量使用,是 spring-bo

springboot加@EnableRedisHttpSession注解后namespace配置失效-爱代码爱编程

配置和注解是配置的两种方式,加注解后,  public void setRedisNamespace(String namespace) {         this.redisNamespace = namespace;     } 该方法得不到调用,不加注解则SpringBootRedisHttpSessionConfiguration类 //

关于使用了@EnableRedisHttpSession注解,在配置文件中加入timeout 无效的原因-爱代码爱编程

spring: session: timeout: 120 首先看下@EnableRedisHttpSession注解属性 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(RedisHttpSessionConfigurat

redis 能不能监听特定的key失效_Redis key 失效通知配置及命令监听-爱代码爱编程

修改 redis.conf 配置 找到notify-keyspace-events 并将notify-keyspace-events 修改为 notify-keyspace-events Ex 配置Ex对应的意思如下: E: 键事件通知,以keysevent@为前缀 x:过期事件(每次key过期时生成) K 键空间通知,以keyspace@为

深入源码分析SpringBoot中使用@ConditionalOnBean无效的问题(@ConditionalOnBean did not find any beans of type)-爱代码爱编程

一、前言 最近在使用SpringBoot的@ConditionalOnBean的时候遇到一个很很奇特的问题。即在@Bean中使用@ConditionalOnBean注解,在可以确保需要依赖的Bean一定在此之前已经存在了,但是@ConditionalOnBean仍然未生效。启动的时候报错:not loaded because @ConditionalOn

@Configuration和@Conditional同时存在的时候导致@Configuration下的Bean失效-爱代码爱编程

本文涉及到的关注点 1. 项目中存在MyConfig和MyConfig2这两个本文中是实验对象 2. 自定义OnBeanCondition 实现Condition ,通过特定条件执行特定的需求 3.Mybean和Mybean2 充当本文中的路人甲,乙 4. ConfigurationCondition充当本文中的幕后 King 5.项目结构目录,

Redis笔记5-爱代码爱编程

P25 SpringBoot整合Redis 说明:在springboot2.x之后,原来使用的jedis换成了lettuce 原因: jedis:采用的直连,多个线程操作的话,是不安全的,想要避免不安全使用jedis pool连接池 lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程数据 1.源码分析,在

Mybatis拦截器失效-爱代码爱编程

现象: 自定义插件注册成功,但是始终不进入拦截器方法; 我的拦截器: 排查 Mybatis拦截器是采用的责任链模式,一般拦截器中intercept方法中最后执行 invocation.proceed() 方法,将拦截器责任链向后传递; 但是查看pageHelper源码可以发现,他的拦截器方法中并没有向后传递责任链,而是直接执行了另一个query方法

Redis之RedisTemplate与RedisUtil-爱代码爱编程

该笔记大部分搬运B站遇见狂神说的Redis,顺便把图文合并记录,便于回顾,仅用于学习! 视频地址:https://www.bilibili.com/video/BV1S54y1R7SB?t=250 作者真的非常好,记得三连 如有侵权,请联系删除! 1、查看源码 @Configuration(proxyBeanMethods = false

条件注解@ConditionalOnBean失效原因-爱代码爱编程

测试环境(配置类) @Import({User.class,Pet.class}) @Configuration(proxyBeanMethods = true) public class MyConfig { @Bean @ConditionalOnBean(name = "cat") public User use

开发技术-java实体类链式赋值简单示例-爱代码爱编程

文章目录 1. 普通的赋值方式2. 使用 @Builder3. 使用@Accessors 1. 普通的赋值方式 这是个非常普通的实体类 public class User { private Str

@import 和 @conditional 和@importresource_importselector与condition-爱代码爱编程

@import(Students.class) 1.将括号中的类放进ioc容器,被放进去的类的name是全类名    com.hxut.rj1192.pojo.Students 所以要获得被import导入的类,必须使用全类名 Car car = applicationContext.getBean("com.hxut.rj1192.pojo.Car