Servlet應用程序需要放置到servlet容器中運行,那麼應用程序需要與容器進行配合運行,就需要使用ServletContext 與 Web 容器通信。例如寫日誌,轉發請求等。
每一個 Web 應用程序含有一個Context,也就是ServletContext,被Web應用內的各個程序共享。因爲Context可以用來保存資源並且共享,所以我所知道的 ServletContext 的最大應用是Web緩存,用於存儲我們應用程序常用的系統參數,數據等;
那麼這個ServletContext如何被創建的呢? 如果ServletContext數據發生變更了怎麼辦呢?
ServletContextListener 此時就登場了!
ServletContextListener 是 ServletContext 的監聽者, 他會監聽ServletContext 發生的變化,如服務器啓動時通過ServletContextListener 來創建初始化ServletContext ,服務器關閉時 ServletContext 將要被銷燬也是通過ServletContextListener 對ServletContext以及存儲的數據進行銷燬。
具體如下:
-
服務器啓動時,ServletContextListener 的 contextInitialized()方法被調用,所以在裏面創建好緩存。可以從文件中或者從數據庫中讀取取緩存內容生成類,用 servletContext.setAttribute()方法將緩存類保存在 ServletContext 的實例中。
-
程序使用 ServletContext.getAttribute()讀取緩存。如果是 JSP,使用application.getAttribute()。如果是 Servlet,使用 getServletContext().getAttribute()。如果緩存發生變化(如訪問計數),你可以同時更改緩存和文件/數據庫。或者你等變化積累到一定程序再保存,也可以在下一步保存。
-
服務器將要關閉時,ServletContextListener 的 contextDestroyed()方法被調用,所以在裏面保存緩存的更改。將更改後的緩存保存迴文件或者數據庫,更新原來的內容。
Spring 中ServletContextListener是如何應用的?
我們知道spring項目在web容器中啓動後,容器會首先讀取web.xml配置文件,如下:
1、在web.xml配置監聽器ContextLoaderListener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Spring 中 ContextLoaderListener的作用就是啓動Web容器時,自動裝配ApplicationContext的配置信息。因爲它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啓動容器時,就會默認執行它實現的方法。
因此ContextLoaderListener幫助spring啓動IoC容器,也就是ContextLoaderListener自動裝配ApplicationContext的配置信息,併產生WebApplicationContext對象,然後將這個對象放置在ServletContext的屬性裏,這樣我們只要得到Servlet就可以得到WebApplicationContext對象,並利用這個對象訪問spring容器管理的bean。
2、部署spring的xml文件
如何部署applicationContext的xml文件,如果在web.xml中不寫任何參數配置信息,默認的路徑是"/WEB-INF/applicationContext.xml,在WEB-INF目錄下創建的xml文件的名稱必須是applicationContext.xml。如果是要自定義文件名可以在web.xml里加入contextConfigLocation這個context參數:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/classes/spring-*.xml
</param-value>
</context-param>
在<param-value> </param-value>裏指定相應的xml文件名,如果有多個xml文件,可以寫在一起並一“,”號分隔。上面的spring-*.xml採用通配符,比如這那個目錄下有spring-mybatis-base.xml,spring-dao.xml等文件,都會一同被載入。
由此可見spring.xml的文件位置就可以有兩種默認實現:
第一種:直接將之放到/WEB-INF下,之在web.xml中聲明一個listener、
第二種:將之放到classpath下,但是此時要在web.xml中加入<context-param>,用它來指明你的spring.xml的位置以供web容器來加載。
以上加載spring的相關配置文件無非是將系統相關資源、數據、參數等加載到內存中,這也就是ServletContextListener完成的最終使命!
Spring Boot也用到了ContextLoaderListener?
目前SpringBoot已經成爲了主流的項目架構,因此就會有人疑問,SpringBoot中會不會也用到了ContextLoaderListener,但是SpringBoot是通過main主函數來啓動的,ContextLoaderListener不是需要在web.xml中配置的嗎?springboot 哪來的web.xml?
那麼我們來看看SpringBoot到底是怎麼用到的ContextLoaderListener?
@SpringBootApplication
@EnableTransactionManagement
@ServletComponentScan
@MapperScan("com.xsxx.mapper")//配置mybatis包掃描
看到上面的代碼是不是感覺知道了什麼?
沒錯!就是註解,spring boot之所以強大,我個人認爲,絕對有註解的功勞啊!
在Springboot web 應用啓動代碼中添加@ComponentScan註解,使我們的Springboot應用在啓動時能掃描到該Listener.
運行項目,我們可以springboot的啓動log看到如下log信息,即表明我們的ServletContextListener註冊成功。