spring boot ValidationAutoConfiguration自动注入MethodValidationPostProcessor类导致bean提前被初始化

前言

最近改一些项目,发现日志平凡的报 is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

INFO PostProcessorRegistrationDelegate$BeanPostProcessorChecker:325 [main]  Bean 'com.alibaba.dubbo.config.RegistryConfig' of type [com.alib
aba.dubbo.config.RegistryConfig] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

虽然报了这些错,但目前对项目并没有什么影响,但还是要看下为什么会有这些问题。

先弄明白这个错是什么意思:名字叫com.alibaba.dubbo.config.RegistryConfigRegistryConfig这个类型是com.alib aba.dubbo.config.RegistryConfig这个bean 不能合法被所有BeanPostProcessors 处理,比如不能合法的被自动代理。

1、什么是beanPostProcess

这里再回顾下beanPostProcess,我们知道spring 通过@autoWire自动注入一些属性,实际就是beanPostProcess帮助我们实现的,说白了beanPostProcess是对bean再次加工的一些处理类,比如说在@Trantional这个注解后,一个beanPostProcess就会帮这个类生成一个代理类,让有@Trantional注解的方法 变成一个事务方法。这就是beanPostProcess的作用。

还有一点要注意:BeanPostProcessor本身也是一个Bean,它的实例化比普通的业务bean要早,如果BeanPostProcessor依赖一些Bean,那么就导致了一些普通Bean的实例化早于BeanPostProcessor。
比如一个普通如果早于自动代理beanPorcessor,那么它就不会被生成代理对象。

2、看下BeanPostProcessorChecker这个报错的地方

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
       //这里就是比较下这个bean实例化时 postProcess个数是否<目标个数,如果小于 说是这个bean在一些BeanPostProcessor的前面初始化了,那么就要注意
	if (bean != null && !(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
			this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
		if (logger.isInfoEnabled()) {
			logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
					"] is not eligible for getting processed by all BeanPostProcessors " +
					"(for example: not eligible for auto-proxying)");
		}
	}
	return bean;
}

3、排查导致这么bean提前初始化的原因

通过日志看,并没能看出什么问题,只能通过断点来排查:
在这里插入图片描述

registerBeanPostProcessors这个方法实际就是注册一些BeanPostProcessors

3.1、查看registerBeanPostProcessors

通过查看registerBeanPostProcessors,发现是遍历orderedPostProcessorNames这个List,调用beanFactory.getBean(ppName, BeanPostProcessor.class) 这个方法实例化某个bean后就打印了那一堆,具体的bean是methodValidationPostProcessor
这个bean是在ValidationAutoConfiguration中自动注入的
在这里插入图片描述
这个方法有2个入参,Environment environment, Validator validator, 而bean的提前注入就是因为初始Environment 这个属性导致的,参数的注入是通过类型注入的,会调用getBeanNamesForType 来获取所有这个类型的候选类实例。
看下调用链:
在这里插入图片描述
doGetBeanNamesForType方法:
在这里插入图片描述
isTypeMatch:这个方法中有一行比较重要
在这里插入图片描述会判断待匹配的类是不是FactoryBean类型,我们这里是Environmet 显然不是,那么它会把FactoryBean这个类型也加入到匹配类中。国为FactoryBean类型getObject方法返回的类型是真正实例的类型。
在这里插入图片描述

注意这里调用的方法是 getTypeForFactoryBean(beanName, mbd);,看实例化bean传入bean名字是什么:
在这里插入图片描述
实例化时会传入&符号,这里提前初始化提factoryBean对象本身,而不是factoryBean.getObject()返回的对象。所以当我们在mapper类上写切面时 还是可以生效的。
我们beanDefinitionMap中存放是不带&符的bean,所以在普通bean实例化中 走代理器 生成代理对象
在这里插入图片描述
最后调用factory.getObject()方法返回真实对象。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

而ReferenceBean又依赖:
com.alibaba.dubbo.config.ApplicationConfig
com.alibaba.dubbo.config.RegistryConfig
com.alibaba.dubbo.config.MonitorConfig
所以,在ReferenceBean之前又实例化了这3个对象。

也就是说所有FactoryBean的对象都会被提前实例化。
SqlSessionFactoryBean``MapperFactoryBean ,而很多mapper其实也是MapperFactoryBean对象,所以也会提前初始化。

4、如何解决

这么看下来,实际就是ValidationAutoConfiguration自动注入MethodValidationPostProcessor导致的,而这个MethodValidationPostProcessor这个bean如果你命名用Validator.class ,那么就是自动注入。
所以需要排除ValidationAutoConfiguration的自动注入,或排除Validator.class所有包。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值