错误回溯
获取spring的上下文,放到静态变量applicationContext
中
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
public static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext args){
applicationContext = args;
}
}
缓存组件,使用单例模式,没有放到容器中
public class CacheComponent {
List<IotOperatorTemplate> iotOperatorTemplates;
private CacheComponent(){
//注意,此处使用了上一步获取的上下文属性applicationContext
IotOperatorTemplateMapper iotOperatorTemplateMapper = (IotOperatorTemplateMapper)ApplicationContextUtil.applicationContext.getBean("iotOperatorTemplateMapper");
iotOperatorTemplates = iotOperatorTemplateMapper.selectList(null);
}
public static class CacheHolder{
private static CacheComponent cacheComponent = new CacheComponent();
}
public static CacheComponent getInstance(){
return CacheHolder.cacheComponent;
}
}
容器中的bean,项目启动就获取缓存组件中的缓存对象
@Component
public class ThirdHuClient implements InitializingBean {
@Override
public void afterPropertiesSet(){
try{
//从缓存组件获取所有运营商模板
IotOperatorTemplate iotOperatorTemplate = CacheComponent.getInstance().getIotOperatorTemplates()
.stream().filter(item -> item.getType().equals(TemplateConstants.THRID_HU.getMessage())).findFirst().get();
}
}
}
然后有service自动注入了ThirdHuClient
,项目启动,报错如下图
分析上图发现,当容器启动时,首先调用了ThirdHuClient
的afterPropertiesSet()
方法,该方法中CacheComponent.getInstance()
触发单例类加载
原因分析
CacheComponent
类加载时,此时ApplicationContextUtil还没有放入到容器,故获取不到应用上下文,所以调用getBean()
方法会抛出NPE。
解决
ThirdHuClient
这个bean的初始化必须依赖ApplicationContextUtil
这个bean,此时主角就出场了,@DependsOn
,在ThirdHuClient
类上加上这个注解,表示先初始化ApplicationContextUtil
。如图所示
结论
有很多场景需要bean B应该被先于bean A被初始化,从而避免各种负面影响。我们可以在bean A上使用@DependsOn注解,告诉容器bean B应该先被初始化