一次Spring Bean初始化顺序问题排查记录
Posted Birding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次Spring Bean初始化顺序问题排查记录相关的知识,希望对你有一定的参考价值。
最近在使用Springboot的时候需要通过静态的方法获取到Spring容器托管的bean对象,参照一些博文里写的,新建了个类,并实现ApplicationContextAware接口。代码大致如下:
@Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if(SpringUtils.applicationContext == null) { SpringUtils.applicationContext = applicationContext; } } public static <T> T getBean(String name,Class<T> clazz){ return getApplicationContext().getBean(name, clazz); } }
然后另外一个bean需要依赖这个静态获取bean的方法,代码大致如下:
@Component public class TestBean{ private Object dependencyBean = SpringUtils.getBean(OtherBean.class); }
(注: 忽略代码逻辑是否合理~~ 这些代码是为演示所用简化的逻辑,肯定有同学会说:既然都是bean了为什么不注入,而是要用静态的获取呢?这个暂时不考虑,暂认为就必须要这样搞)
这两个类的层次结构和包名大致如下:
utils
> notice
> TestBean
> SpringUtils
就是TestBean在SpringUtils的下一级,TestBean所在包名为notice(这这个名字很重要! 直接影响到这两个bean的加载顺序,具体原理往下看)
代码就这么多,从以上代码来静态分析看,确实有些漏洞,因为没有考虑到Spring bean的加载顺序,可能导致的SpringUtils报空指针异常(在TestBean先于SpringUtils初始化的场景下),不管怎么样先执行一下看下效果,效果如下:
macOS操作系统下代码正常
windows平台下代码空指针异常
为什么这还跟平台有关了呢?难道Spring bean的初始化顺序还跟平台有关?事实证明这个猜想是正确的。下面从Spring源代码里找原因。
普通的(什么样的bean算是普通?这里暂定用@Component注解的bean)Spring bean的加载包括两个部分,第一部分是加载bean的定义,第二部分是实例化bean。这个可以在AbstractApplicationContext.refresh方法里找到对应:
以上是关于一次Spring Bean初始化顺序问题排查记录的主要内容,如果未能解决你的问题,请参考以下文章
spring bean实例化过成中各种初始化的顺序 beanPost顺序和时机
spring bean实例化过成中各种初始化的顺序 beanPost顺序和时机