監聽器中spring注入相關的問題


問題描述: 需求是要求在項目啟動自動觸發一個service中的線程的操作,使用監聽器來實現,但是自定義監聽器中spring注解service失敗,通過WebApplicationContextUtils去spring容器中獲取仍然獲取不到,通過斷點查看spring容器中沒有被注入的service對象   代碼如下: 1、web.xml文件中配置監聽器
<listener>
<listener-class>com.cairh.xpe.aips.web.Test.TestLinstener</listener-class>
</listener>

 2、寫監聽器實現ServletContextListener並重寫相應的方法

public class TestLinstener implements ServletContextListener{

@Autowired
MessMediaService messMediaService;

@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(
"*************執行相關方法************");
//spring容器中獲取service對象
MessMediaService service = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(MessMediaService.class);
service.test();
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}

}

3、service類

@Lazy(false)
@Service
public class MessMediaService {

@Autowired
private ITaskService taskService;

private RedisLock redisLock = new RedisLock();

private Map taskMap = (Map)JSON.parse(RedisClientUtil.get("config.cache./aips/tasksettings.properties"));

private Thread thread = new Thread(new Runnable() {

@Override
public void run() {

}
});

public int test(){
    taskService.test();
     ...
return 1;
}

public MessMediaService() {
super();
System.out.println(
"*******************測試構造方法********************");
}

@PostConstruct
private void init() throws Exception {
System.out.println(
"*******************init******************");
thread.start();
}

}

 

 解決歷程:

后來嘗試在構造方法中觸發事件也失敗,因為斷點並沒有進入到構造方法中;再后來嘗試使用@PostConstruct注解讓service在實例化過程中自動執行方法來實現,@PostConstruct執行順序大致如下:服務器加載servlet-->servlet構造函數-->@PostConstruct方法-->init-->service方法-->destroy方法-->@PreDestory方法-->服務器卸載servlet完畢 通過此方法正常來說也可實現項目啟動自動觸發一定的操作,但是啟動時並沒有按照預想進入到注解的方法中執行任何操作注:@PostConstruct詳細解釋見:@PostConstruct與@PreDestroy講解及實例 分析:構造方法沒有執行並且spring容器中沒有messMediaService實例,說明要么沒有實例化要么是實例化失敗首先驗證是否實例化失敗,在普通的controller中注入此service,在調用controller時成功,說明service本身沒有錯誤,不會導致實例化失敗,剩下的可能就是在項目啟動加載的時候沒有實例化service 在查看spring配置文件的時候發現了beans屬性default-lazy-init="true",發現問題所在,此屬性表示延時加載,為了提高平時開發中項目啟動時間設置的,就是在IoC容器啟動時不會實例化bean,只有當容器需要用到時才實例化它,故在監聽器中並沒有實例化service 解決:如果是手動配置則可在bean屬性中添加lazy-init="false"屬性來對需要提前加載的bean在spring容器啟動時實例化,或者使用注解標簽@Lazy(false) 再次嘗試:1、監聽器中注入messMediaService依然失敗;2、spring容器中獲取messMediaService對象成功,可通過從spring容器中獲取messMediaService對象來調用,可滿足需求;3、在messMediaService構造方法中斷點發現執行到service構造方法時service中注入的taskService依然為null;4、在@PostConstruct注解方法中發現messMediaService中注入的taskService也有了實例,此方法可成功解決問題; 總結:項目啟動最先加載context-parame標簽中配置的spring文件,此文件中配置了spring需要實例化的bean目錄,但是spring注入和bean的實例化不是同時的,先實例化再注入,兩步操作是緊接着的,但是在實例化調用構造方法完成后才有依賴注入行為。注:spring實例化詳細解釋見:spring容器初始化過程 和 Spring BeanFactory實例化Bean的詳細過程 項目啟動執行順序:調用構造方法實例化-->調用@PostConstruct方法-->執行listener的contextInitialized方法 listener中messMediaService沒有注入成功而messMediaService中能注入taskService是因為messMediaService實例化時其屬性service屬於一種依賴關系也會被實例化並注入進來,而listener不會被spring實例化並查找依賴關系,故監聽器中不能使用spring注解,只能手動獲取spring容器中對象

 

 

 

 
    

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com