问题现场
SmartInitializingSingleton是spring的扩展点之一,主要用于在Spring容器启动完成时进行扩展操作,即afterSingletonsInstantiated()。接口的bean的作用域必须是单例,afterSingletonsInstantiated()才会触发。
问题代码:代码中实现了spring提供的SmartInitializingSingleton接口,并实现了afterSingletonsInstantiated方法,但是却不执行。
代码如下:
@Configuration
public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("TestSmartInitializingSingleton.afterSingletonsInstantiated ===========>");
}
}
application.yaml中配置了懒加载
spring:
main:
lazy-initialization: true
现象:
- 启动项目发现在SpringBoot 2.2.6.RELEASE版本下afterSingletonsInstantiated不执行,升级SpringBoot版本2.6.11之后afterSingletonsInstantiated执行了。
- 在低版本中去掉yaml中懒加载配置也能成功执行。
所以高版本该是已经解决了这个问题,但是工作的项目SpringBoot版本一般不轻易升级。所以需要在不升级版本的情况下找到低版本和高版本的区别并找到解决方法。(不想去掉懒加载)
发现问题
先去掉懒加载配置并在低版本afterSingletonsInstantiated方法上打断点,查看调用栈发现调用的地方在
DefaultListableBeanFactory.preInstantiateSingletons
现在我们打开懒加载并在这个for循环上打上条件断点
发现运行到这行的时候这个bean是null
于是看代码发现861行,懒加载的bean不会实例化
于是现在的问题是这个bean的lazyInit为啥是true
查看代码发现lazyInit字段在LazyInitializationBeanFactoryPostProcessor的postProcessBeanFactory方法中修改成了true
总算是找到了原因了,那为啥高版本没有问题呢? 通过debug发现高版本中多了个LazyInitializationExcludeFilter过滤器。
这个过滤器作用是判断bean是否为SmartInitializingSingleton实现,如果是则排除,也即不会设置lazyInit为true。
解决方案
发现了问题之后,解决就简单了,只要在低版本下实现一个LazyInitializationExcludeFilter过滤器排除SmartInitializingSingleton就好。
哈哈,果然afterSingletonsInstantiated执行了
再问
为啥这个方法是否执行和全局懒加载相关?
当这个配置是true的时候,会添加LazyInitializationBeanFactoryPostProcessor