springboot项目在BeanDefinitionRegistryPostProcessor中修改BeanDefinition不生效

环境

mybatis-plus版本:3.3.1,对应mybatis版本:3.5.3,mybatis-spring版本:2.0.3

问题描述

由于在springboot项目启动时需要修改某个FactoryBean的BeanDefinition属性,于是向springboot容器中注入了BeanDefinitionRegistryPostProcessor实现类,实现了postProcessBeanDefinitionRegistry方法来修改BeanDefinition中的属性,但是怎么都不生效

问题分析

进入到springboot启动时AbstractApplicationContext类的invokeBeanFactoryPostProcessors(beanFactory)方法中,在这个方法中会进行容器中BeanDefinitionRegistryPostProcessor的调用,发现mybatis启动时向容器中注入了MapperScannerConfigurer,而在回调这个类的postProcessBeanDefinitionRegistry方法中,有下面一段代码

 Map<String, PropertyResourceConfigurer> prcs = 
   										applicationContext.getBeansOfType(PropertyResourceConfigurer.class);

大家有兴趣可以自己debug看下,大致就是获取容器中的PropertyResourceConfigurer对象,调用ApplicationContext的getBeansOfType方法获取对应类型的bean时,它会首先获取所有的BeanDefinition,在首次获取时将原始的beanfefinition包装成RootBeanDefinition放入到mergedBeanDefinitions缓存中,然后挨个解析BeanDefinition对应的class,但是有一个BeanDefinition比较特殊,就是FactoryBean,由于前面的applicationContext.getBeansOfType(PropertyResourceConfigurer.class默认调用getBeansOfType(type, true, true);,意思就是如果解析不出beandefinition,那么就初始化后来解析。

解析Factorybean对应BeanDefinition中的class

由于上面指定了可以进行初始化,执行关键代码

if (allowInit) {
	FactoryBean<?> factoryBean = (mbd.isSingleton() ?
			getSingletonFactoryBeanForTypeCheck(beanName, mbd) :
			getNonSingletonFactoryBeanForTypeCheck(beanName, mbd));
	if (factoryBean != null) {
		// Try to obtain the FactoryBean's object type from this early stage of the instance.
		Class<?> type = getTypeForFactoryBean(factoryBean);
		if (type != null) {
			return ResolvableType.forClass(type);
		}
		// No type found for shortcut FactoryBean instance:
		// fall back to full creation of the FactoryBean instance.
		return super.getTypeForFactoryBean(beanName, mbd, true);
	}
}
  1. 获取BeanDefinition中的getDecoratedDefinition,看是否对应的BeanDefinition能获取到对应的class
  2. 如果上面的没有获取到,那么实例化这个FactoryBean,然后调用getObjectType
  3. 如果还是不能解析到对应的class,那么springboot容器就是创建这个bean,然后再调用getObjectType方法,而这时创建的这个bean的BeanDefinition是从mergedBeanDefinitions,它从第一次在invokeBeanFactoryPostProcessors后就不会改变了,直到invokeBeanFactoryPostProcessors方法调用结束

总结前面产生的原因

在解析Factorybean对应的class时,如果满足下面两个条件:

  1. mergedBeanDefinitions中缓存的BeanDefinition没被修改
  2. 在调用applicationContext的getBeansOfType方法时,指定了allowEagerInit为true

那么springboot有可能会把这个bean提前创建好放入springboot容器中去,所以我们在BeanDefinitionRegistryPostProcessor中的修改就不起作用了!!!

解决

两种办法:

  1. 第一种方法:替换mybatis-spring版本为2.0.5,笔者注意到在mybatis后续版本中已经解决了这个问题(也许是bug)
  2. 第二种方法包含下面几步:
    • 保留现在出问题的mybatis-spring版本
    • BeanDefinitionRegistryPostProcessor的实现类,也要实现PriorityOrdered或者Ordered类。
    • 接着,在BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法中,在修改BeanDefinition属性之前先调用BeanDefinitionRegistry(其实就是DefaultListableBeanFactory)的clearMetadataCache方法,清除mergedBeanDefinitions中的缓存

写在最后

如果对你有帮助,请给个赞吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值