舉例:springweb-2 項目(在 spring-web 項目基礎(chǔ)上修改)
對于 Web 應(yīng)用來說,ServletContext 對象是唯一的,一個 Web 應(yīng)用,只有一個ServletContext 對象,該對象是在 Web 應(yīng)用裝載時初始化的。若將 Spring 容器的創(chuàng)建時機(jī),放在 ServletContext 初始化時,就可以保證 Spring 容器的創(chuàng)建只會執(zhí)行一次,也就保證了Spring 容器在整個應(yīng)用中的唯一性。
當(dāng) Spring 容器創(chuàng)建好后,在整個應(yīng)用的生命周期過程中,Spring 容器應(yīng)該是隨時可以被訪問的。即,Spring 容器應(yīng)具有全局性。而放入 ServletContext 對象的屬性,就具有應(yīng)用的全局性。所以,將創(chuàng)建好的 Spring 容器,以屬性的形式放入到 ServletContext 的空間中,就保證了 Spring 容器的全局性。
上述的這些工作,已經(jīng)被封裝在了如下的 Spring 的 Jar 包的相關(guān) API 中: spring-web-4.3.9.RELEASE
在Web項目中使用Spring,需要導(dǎo)入Spring對Web的支持包:spring-web-RELEASE。
該包在 Spring 框架的解壓目錄下的 libs 目錄中。
若要在ServletContext初始化時創(chuàng)建Spring容器,就需要使用監(jiān)聽器接口ServletContextListener對ServletContext進(jìn)行監(jiān)聽。在web.xml中注冊該監(jiān)聽器。
Spring 為該監(jiān)聽器接口定義了一個實現(xiàn)類 ContextLoaderListener,完成了兩個很重要的工作:創(chuàng)建容器對象,并將容器對象放入到了 ServletContext 的空間中。
打開 ContextLoaderListener 的源碼。看到一共四個方法,兩個是構(gòu)造方法,一個初始化方法,一個銷毀方法。
所以,在這四個方法中較重要的方法應(yīng)該就是 contextInitialized(),context 初始化方法。
跟蹤 initWebApplicationContext()方法,可以看到,在其中創(chuàng)建了容器對象。
并且,將創(chuàng)建好的容器對象放入到了 ServletContext 的空間中,key 為一個常量:
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。
ContextLoaderListener 在對 Spring 容器進(jìn)行創(chuàng)建時,需要加載 Spring 配置文件。其默認(rèn)的 Spring 配置文件位置與名稱為:WEB-INF/applicationContext.xml。但,一般會將該配置文件放置于項目的 classpath 下,即 src 下,所以需要在 web.xml 中對 Spring 配置文件的位置及名稱進(jìn)行指定。
從監(jiān)聽器 ContextLoaderListener 的父類 ContextLoader 的源碼中可以看到其要讀取的配置文件位置參數(shù)名稱
contextConfigLocation。
在 Servlet 中獲取容器對象的常用方式有兩種:
● 直接從 ServletContext 中獲取
從對監(jiān)聽器 ContextLoaderListener 的源碼分析可知,容器對象在 ServletContext 的中存放的 key 為
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。所以,可以直接通過 ServletContext 的 getAttribute()方法,按照指定的 key 將容器對象獲取到。
● 通過 WebApplicationContextUtils 獲取
工具類 WebApplicationContextUtils 有一個方法專門用于從 ServletContext 中獲取 Spring容器對象:
getRequiredWebApplicationContext(ServletContext sc)
查其源碼,看其調(diào)用關(guān)系,就可看到其是從 ServletContext 中讀取的屬性值,即 Spring容器。
以上兩種方式,無論使用哪種獲取容器對象,刷新 success 頁面后,可看到代碼中使用 的 Spring 容器均為同一個對象。