ServletContextListener的流程筆記
public interface ServletContextListener extends EventListener {public default void contextInitialized(ServletContextEvent sce) {}public default void contextDestroyed(ServletContextEvent sce) {}}
public class MyServletContextListener implements ServletContextListener {public void contextInitialized(ServletContextEvent sce) {System.out.println(sce.toString());System.out.println("--------wo de 初始化");}public void contextDestroyed(ServletContextEvent sce) {System.out.println(sce.toString());System.out.println("--------emmm....wo死了。。。");}}
public class MyServletConfig {/*** 初始化一個(gè)servlet監(jiān)聽器* @return servlet監(jiān)聽器注冊(cè)器*/public ServletListenerRegistrationBean servletListenerRegistrationBean(){ServletListenerRegistrationBean servletListenerRegistrationBean=new ServletListenerRegistrationBean();servletListenerRegistrationBean.setListener(new MyServletContextListener());return servletListenerRegistrationBean;}}
啟動(dòng)和停止的效果如下:


我們一路找到啟動(dòng)的方法,發(fā)現(xiàn)這塊的過濾器也是在此進(jìn)行初始化的。

我們重點(diǎn)看一下listerner的初始化
//獲取所有的監(jiān)聽器Object instances[] = getApplicationLifecycleListeners();if (instances == null || instances.length == 0) {return ok;}ServletContextEvent event = new ServletContextEvent(getServletContext());ServletContextEvent tldEvent = null;if (noPluggabilityListeners.size() > 0) {noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());tldEvent = new ServletContextEvent(noPluggabilityServletContext);}for (Object instance : instances) {if (!(instance instanceof ServletContextListener)) {continue;}ServletContextListener listener = (ServletContextListener) instance;try {fireContainerEvent("beforeContextInitialized", listener);if (noPluggabilityListeners.contains(listener)) {listener.contextInitialized(tldEvent);} else {listener.contextInitialized(event);}fireContainerEvent("afterContextInitialized", listener);} catch (Throwable t) {ExceptionUtils.handleThrowable(t);fireContainerEvent("afterContextInitialized", listener);getLogger().error(sm.getString("standardContext.listenerStart",instance.getClass().getName()), t);ok = false;}}return ok;
我們發(fā)現(xiàn)我們的applicationContext就包括了我們的listener

而上層調(diào)用我們的serveletlistener是誰?我們?cè)谘b配到spring上下文的時(shí)候是registerBean,那么肯定和這個(gè)類具有很大的關(guān)系。我們一直跟蹤。

發(fā)現(xiàn)在tomcat啟動(dòng)的時(shí)候會(huì)將將所有的register傳入,并執(zhí)行onstarter方法,而每個(gè)register都自帶了其listerner之類的子成員。所以操作起來也沒有任何問題。

我們一路跟蹤,尋找我們得beanregister是如何傳入到tomcat得啟動(dòng)代碼中。
我們繼續(xù)向上查看。

在創(chuàng)建tomcat服務(wù)端得時(shí)候,會(huì)將initializer作為參數(shù)傳入。而這里得initializer就是我們得ServletListenerRegistrationBean注冊(cè)器,作為spring上下文得子類,可以獲取到注冊(cè)到ioc中得得任何對(duì)象。所以這塊我們就明白了其與spring得整合原理。因?yàn)槠浔旧砭褪莝pring得一部分。

之所以和tomcat發(fā)生了關(guān)系,是因?yàn)槲覀冊(cè)诔跏蓟脮r(shí)候?qū)pring注冊(cè)得這些servletcontextlistener、filter等等當(dāng)作參數(shù)去初始化tomcat,這就完成了從spring得bean到servlet容器得一般過程。

上邊分析了很多,大概得過程就是那樣。這里再小結(jié)一下:我們通過@Bean注解將我們得servletlistener、filter等注冊(cè)到spring容器中,但是在tomcat初始化的時(shí)候?qū)⑦@些servlet容器需要的類通過beanfactory拿到并作為參數(shù)去初始化tomcat。從而完成bean的管理在spring中,而具體使用在tomcat中。ServletContextListener的用處還是比較廣泛的,因?yàn)楹芏鄷r(shí)候我們需要在項(xiàng)目啟動(dòng)之前做一些事情,或者在項(xiàng)目停止之后做一些事情,而且這些事情是專門針對(duì)servlet容器的這種應(yīng)用?,F(xiàn)在想一下有那些場(chǎng)景吶?比如說我們做一些異步的監(jiān)控,那么我們可以采用ServletContextListener 去創(chuàng)建定時(shí)任務(wù)線程然后去收集一些數(shù)據(jù),當(dāng)然這只是一種方式,我們也可以采用springapplicationlisenter的事件監(jiān)聽器都可以做。好了,文章就寫這里了。
安了~
