---恢復內容開始---web
問題:在一個web應用中我使用了spring框架,但有一部分模塊或組件並無託管給Spring,好比有的多是一個webservice服務類,若是我想在這些非託管的類裏使用託管對象該怎麼辦呢,很天然的咱們須要得到spring容器對象的引用ApplicationContext,個人想法是在服務啓動後,想辦法將ApplicationContext容器的應用保存到一個靜態變量中,之後使用就簡單了。spring
1)剛開始用的是spring+struts2,實力話spring用的是ContextLoaderListener,以下緩存
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/conf/comm/applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
這種狀況下經過寫一個listener,在web.xml配置在spring的實例化以後就行,在contextInitialized方法中保存spring容器mvc
public class ApplicationContextListener implements ServletContextListener{ public void contextDestroyed(ServletContextEvent arg0) { } public void contextInitialized(ServletContextEvent event) { C.wac = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext()); System.out.println("存儲spring 容器結束:ApplicationContext="+C.wac); } }
2)今天寫一個新項目,想嘗試一下spring mvc,邊學邊作,第一件事天然是將spring+struts2中的一些東西以spring mvc的方式映射過來,哪不會學哪,天然保存spring容器的引用成爲了其中一項映射工做,由於spring mvc的初始化用的是一個servlet(DispatcherServlet),因此不可能再用listener來保存容器(實例化順序listener -> filter -> servlet),剛開始想的是用servlet,經過配置<load-on-startup>控制servlet的實例化在spring的servlet以後,但不知爲何就是沒法得到spring容器,一直報空指針異常。最後沒辦法只能放棄。只能換思路了,在網上找到一個ApplicationContextAware接口,實現該接口的託管對象在被實例化時spring會經過setApplicationContext方法將ApplicationContext對象傳入這和struts2中SessionAware等的設計是同樣的,測試能夠得到spring容器對象的引用,以下(這裏有點小知識,spring在啓動時對於單例對象會直接實例化,因此配置該對象時不用設置Scope,採用默認便可)app
@Component public class InitComponent implements ApplicationContextAware{ @Override public void setApplicationContext(ApplicationContext ac) throws BeansException { //存儲spring容器引用 C.wac = ac; } }
3)經過實現ApplicationContextAware已能得到容器引用,但有一個問題,若是你但願在spring容器實例化完作點事,好比啓動一個維護線程作點維護工做,該工做可能要用到spring容器裏的東東。則上面的方法並不能保證你得到spring容器引用時spring容器已初始化完畢。進一步搜搜搜發現spring提供了一些事件監聽框架
spring提供了內置的幾類的事件:ContextClosedEvent 、ContextRefreshedEvent(spring實例化完) 、ContextStartedEvent(spring實例化以前) 、ContextStoppedEvent(spring銷燬後) 、RequestHandleEventide
其中的ContextRefreshedEvent正式咱們須要的,在spring容器啓動完成後會觸發ContextRefreshedEvent事件,監聽方法以下,實現測試
ApplicationListener,泛型參數傳ContextRefreshedEvent,對於其它事件的監聽相似
@Component public class InitListener implements ApplicationListener<ContextRefreshedEvent>{ @Override public void onApplicationEvent(ContextRefreshedEvent e) { WebApplicationContext wac = (WebApplicationContext)e.getApplicationContext(); //存儲spring容器引用 C.wac = wac; System.out.println(C.wac); //存儲配置文件路徑 C.CONF_PATH = wac.getServletContext().getRealPath("/WEB-INF/conf"); System.out.println(C.CONF_PATH); //初始化log4j PropertyConfigurator.configure(C.CONF_PATH+"/comm/log4j.properties"); //啓動系統緩存 C.wac.getBean(CacheManager.class).start(); } }
---恢復內容結束---spa