錯誤回溯
獲取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應該先被初始化