項目中沒用spring 的restTemplate 而是采用 jersey來做rest 的實現,一直用着,也沒發現有什么不對,后來加入了,以quartz用硬編碼方式實現,結果啟動項目的時候報錯 ,具體信息為job id重復。后來經排查是因為:jersey依賴於org.springframework.web.context.ContextLoaderListener初始化 的ApplicationContext,而spring mvc 依賴於org.springframework.web.servlet.DispatcherServlet初始化的ApplicationContext,也就是說jersey和spring mvc 雖然是共用一個ApplicationContext但是ApplicationContext被初始化了兩次,每次都會調用 beanFactory.preInstantiateSingletons()方法,導致了單例的類被初始化兩次,平常使用是沒問題的,只是每個單例類都實例化了兩個對像(bean工廠中,你訪問到的是第二次實例化的),恰巧我們的項目中,SchedulJobManager實例化后我們要設置一些JOB ,且這個JOB的ID是不能重復的,就觸發了這個BUG。jersey版本比較老1.4.1,不知新版本的 jersey會不會不存在這問題,且最后我通過修改spring AbstractApplicationContext源碼 解決了這問題,具體排查解決過程如下如下圖
很是奇怪,然后在構造函數中加了一個日志輸出,下如圖所示,結果發現 Schedul Initializing 這行條了兩次
接下來,檢查web.xml 的配置 如下圖所示
后來還懷疑過是不是 jersey這個springServlet搞的鬼,去掉他,還是有同樣的錯 ,當時對這事,有個臨時的解決辦法,加一個全局靜態變量 haveInit,在構造函中設置它為true PostConstruct標簽的方法run方法中,如haveInit為true 就什么也不錯返回。問題是解決了,但不是從根本上解決,於是我在代碼中加了調用棧的打印。如圖所示
打印出來的結果是 ,org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet分別都初始化了一次 appcationContext導致的,請看下圖
解決辦法是修改 spring AbstractApplicationContext類,做這樣的修改:加一個全局靜態變量 haveInitFlg缺省值為0 ,在finishBeanFactoryInitialization方法中
最后一行代碼beanFactory.preInstantiateSingletons(); 修改為
if(haveInitFlg==0){
beanFactory.preInstantiateSingletons();
haveInitFlg = 1;
}
即可