在給新同事培訓Spring MVC時,有人問:可以不配置ContextLoaderListener嗎
所謂ContextLoaderListener,就是在web部署描述符即web.xml里面經常配置的一個監聽器,如下
那么配合它一起使用的,經常是context-param,用來指定Spring要加載的配置文件,比如
上面兩段就是在使用Spring MVC時,常用的配置,DispatcherServlet作為Spring MVC控制器的核心調度器
至于 teach-servlet.xml 就是配置一些Spring MVC需要使用的視圖解析器等等
那么問題是:listener節點可以不配置嗎?答案是肯定的:可以不做任何配置!
查看了ContextLoaderListener源代碼,發現它繼承自ContextLoader,并且實現ServletContextListener接口
肯定得實現這個接口了,不然怎么作為Servlet的監聽器呢。。。
ContextLoaderListener 源代碼很簡單,核心是實現了 ServletContextListener 的contextInitialized和contextDestroyed方法
我們看下類圖結構,只列出一部分屬性和方法
因為 contextInitialized和contextDestroyed 方法分別調用了 ContextLoader里面的initWebApplicationContext和closeWebApplicationContext方法
所以核心最終還是 ContextLoader 實現了這個監聽器,那這個監聽器實現了什么功能呢,我們發現有兩個重要屬性
contextConfigLocation:即在web.xml里面指定的配置文件所在目錄,如果不指定,Spring 會加載WEB_INF目錄下,符合 *Context.xml 或 spring*.xml 規則的文件
currentContextPerThread:保存了當前WebApplicationContext
其實監聽器的加載過程可以描述為:
先判WebApplicationContext是否已存在,不存在的話則初始化一個XmlWebApplicationContext(WebApplicationContext的子類),并把該實例put到 currentContextPerThread 中。而初始化 XmlWebApplicationContext 時,就跟我們使用 new ClassPathXmlApplicationContext(contextConfigLocation)一樣
將我們配置的各種bean都添加到XmlWebApplicationContext中,所以我們知道?ApplicationContext 提供各種 getBean的方法。。。
并且可以發現 ContextLoader還提供了獲取當前 WebApplicationContext的靜態方法:之所以能獲取,是因為initWebApplicationContext初始化方法把創建的XmlWebApplicationContext 塞到了 currentContextPerThread 中
說了一堆,跟Spring MVC 不配置ContextLoaderListener有什么關系呢。。。
因為 ContextLoaderListener 本質上是創建了一個 WebApplicationContext ,所以你的項目里面,如果不使用 WebApplicationContext 就可以不配置該節點。
那么只要做這種配置也是可以的:
發現Spring MVC 所需的配置文件不使用context-param節點指定,直接在DispatcherServlet里面配置即可
注意:這種情況下,你的應用程序是無法使用WebApplicationContext的
正常情況下,都會配置ContextLoaderListener,因為我們知道Spring IOC的兩種實現
基礎的就是BeanFactory,高級的就是ApplicationContext,除非在資源非常有限的情況下,才使用BeanFactory
否則都使用ApplicationContext,而WebApplicationContext就是其中的一種高級實現,它能提供很多有用的方法
那么在應用程序如何獲取 WebApplicationContext 呢,有多種方式,最簡單的就是
這個很熟悉了吧,剛才提到了,當前應用的WebApplicationContext就保存在 ContextLoader的currentContextPerThread屬性當中
還有基于ServletContext上下文獲取的方式
還有一些更合適的,基于Spring提供的抽象類或者接口,在初始化Bean時注入ApplicationContext
繼承自抽象類ApplicationObjectSupport
說明:抽象類ApplicationObjectSupport提供getApplicationContext()方法,可以方便的獲取到ApplicationContext。
Spring初始化時,會通過該抽象類的setApplicationContext(ApplicationContext context)方法將ApplicationContext 對象注入。
繼承自抽象類WebApplicationObjectSupport
說明:類似上面方法,調用getWebApplicationContext()獲取WebApplicationContext
說明:實現該接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 對象。
Spring初始化時,會通過該方法將ApplicationContext對象注入。