Context我們通常解釋為上下文環(huán)境,我想用“容器”來表述它更容易理解一些映九。
1.ServletContext
ServletContext
梦湘,即Servlet容器。首先件甥,對于一個web應用捌议,其部署在web容器中,web容器
提供其一個全局的上下文環(huán)境引有,這個上下文就是ServletContext瓣颅,其包含從容器環(huán)境中獲得的初始化信息,提供對應用程序中所有Servlet共有的各種資源
和功能
的訪問譬正,為后面的spring IoC容器提供宿主環(huán)境宫补。在啟動一個web應用時,ServletContext會為它創(chuàng)建一個ServletContext對象曾我,每個web應用有唯一的ServletContext對象粉怕。
(1)多個Servlet通過ServletContext對象訪問上文屬性
ServletConfig對象中維護了ServletContext對象的引用,開發(fā)人員在編寫servlet時抒巢,可以通過ServletConfig.getServletContext方法獲得ServletContext對象贫贝。
servlet可以通過名稱將對象屬性綁定到上下文,可以被同一個web應用的其他servlet使用蛉谜。
setAttribute
getAttribute
getAttributeNames
removeAttribute
示例:
// 獲取ServletContext對象
ServletContext context = this.getServletContext();
context.setAttribute("appName", "webApp");
在其它的Servlet中利用ServletContext對象獲取
ServletContext context = this.getServletContext();
String name = context.getAttribute("appName");
(2)獲取WEB應用的初始化參數(shù)
getInitParameter
getInitParameterNames
在web.xml文件中配置需要初始化的參數(shù)信息
<web-app>
<context-param>
<param-name>url</param-name>
<param-value>http://localhost:3306/web</param-value>
</context-param>
</web-app>
獲取初始化參數(shù)
ServletContext context = this.getServletContext();
//獲取指定名稱的初始化參數(shù)
String url = context.getInitParameter("url");
//獲取web.xml文件中所有的初始化應用參數(shù)
Enumeration<String> enumer = context.getInitParameterNames();
(3)實現(xiàn)Servlet的轉發(fā)
ServletContext context = this.getServletContext();
//根據(jù)轉發(fā)的地址獲取 RequestDispatcher對象
RequestDispatcher rd = context.getRequestDispatcher("/index.jsp");
//調(diào)用轉發(fā)方法 以下采用任意方法即可
rd.forward(request, response);
//rd.include(request, response);
注意:forward與include的區(qū)別 :
forward方法調(diào)用后在響應中的沒有提交的內(nèi)容被自動消除稚晚,原先Servlet的執(zhí)行則終止。將請求轉發(fā)給其他的Servlet后型诚,由被調(diào)用的Servlet負責對請求做出響應客燕。
include方法使原先的Servlet和轉發(fā)到的Servlet都可以輸出響應信息,即原先的Servlet還可以繼續(xù)輸出響應
(4)用ServletContext對象讀取資源文件
getResource
getResourceAsStream
getResource和getResourceAsStream
讀取資源文件的三種方式狰贯,獲取實現(xiàn)的代碼如下:
ServletContext context = this.getServletContext();
//第一種方式
URL url = context.getResource("WEB-INF/classes/db.properties");
InputStream is = url.openStream();
//第二種方式
// 讀取db.properties文件
String path =context.getRealPath("WEB-INF/classes/db.properties");
// 根據(jù)文件的路徑 構建文件對象
File file = new File(path);
// 根據(jù)file文件對象 創(chuàng)建輸入流
InputStream is = new FileInputStream(file);
//第三種方式
InputStream is = context.getResourceAsStream("WEB-INF/classes/db.properties ");
Web服務器可能支持一個服務器上多個邏輯主機共享一個IP地址也搓。這功能有時被稱為“虛擬主機”。這種情況下暮现,每一個邏輯主機必須有它自己的servlet上下文还绘。Servlet上下文不可以被多個虛擬主機共享
。
2.WebApplicationContext
在web應用中栖袋,會使用到WebApplicationContext,它繼承自ApplicationContext抚太,但是與之不同的是WebApplicationContext
需要ServletContext塘幅,也就是說它必須擁有Web容器的前提下才能完成啟動的工作昔案。它允許從相對于web根目錄的路徑中加載配置文件完成初始化工作。
在web.xml中會提供有contextLoaderListener电媳。在web容器啟動
時踏揣,會觸發(fā)容器初始化事件。此時contextLoaderListener 會監(jiān)聽到這個事件匾乓,其調(diào)用contextInitialized方法捞稿,在這個方法中,spring會初始化一個啟動上下文拼缝,這個上下文被稱為根上下文
娱局,即WebApplicationContext,這是一個接口類咧七,其實際的實現(xiàn)類是XmlWebApplicationContext衰齐。這個就是spring的IoC容器,其對應的Bean定義的配置由web.xml中的context-param標簽指定继阻。在這個IoC容器初始化完畢后耻涛,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE
為屬性Key,將其存儲到ServletContext中.
(1)在web.xml初始化WebApplicationContext:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--or -->
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
有兩種方法:
一種是用ContextLoaderListener這個Listerner瘟檩,另一種是ContextLoaderServlet這個Servlet抹缕,這兩個方法都是在web應用啟動的時候來初始化WebApplicationContext,我個人認為Listerner要比 Servlet更好一些墨辛,因為比起Listerner監(jiān)聽應用的啟動和結束歉嗓,而Servlet得啟動要稍微延遲一些,如果在這時要做一些業(yè)務的操作背蟆,啟動的前后順序是有影響的鉴分。
那么在ContextLoaderListener和ContextLoaderServlet中到底做了什么呢?
以ContextLoaderListener為例带膀,我們可以看到:
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
protected ContextLoader createContextLoader() {
return new ContextLoader();
}
ContextLoader 是一個工具類志珍,用來初始化WebApplicationContext,其主要方法就是initWebApplicationContext垛叨,我們繼續(xù)追蹤initWebApplicationContext這個方法(Spring中的源碼)伦糯,ContextLoader是把WebApplicationContext ( XmlWebApplicationContext是默認實現(xiàn)類)放在了 ServletContext中,ServletContext也是一個“容器”嗽元,也是一個類似Map的結構敛纲,而 WebApplicationContext在ServletContext中的KEY就是WebApplicationContext.ROOT_WEB_APPLICA TION CONTEXT ATTRIBUTE丰辣,我們?nèi)绻褂?WebApplicationContext 則需要從ServletContext取出傅物,Spring提供了一個 WebApplicationContextUtils類,可以方便的取出WebApplicationContext迅诬,只要把 ServletContext傳入就可以了佩谷。
(2)從ServletContext中獲取WebApplicationContext
WebApplicationContext ctx=
WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
3.DispatcherServlet
contextLoaderListener監(jiān)聽器初始化完畢后旁壮,開始初始化web.xml中配置的Servlet监嗜,這個servlet可以配置多個,以最常見的DispatcherServlet為例抡谐,這個servlet實際上是一個標準的前端控制器裁奇,用以轉發(fā)、匹配麦撵、處理每個servlet請求刽肠。DispatcherServlet上下文在初始化的時候會建立自己的IoC上下文,用以持有spring mvc相關的bean免胃。在建立DispatcherServlet自己的IoC上下文時音五,會利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE
先從ServletContext中獲取之前的根上下文(即WebApplicationContext)作為自己上下文的parent上下文。有了這個parent上下文之后杜秸,再初始化自己持有的上下文放仗。這個DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化處理器映射撬碟、視圖解析等诞挨。這個servlet自己持有的上下文默認實現(xiàn)類也是xmlWebApplicationContext。初始化完畢后呢蛤,spring以與servlet的名字相關的屬性為屬性Key(此處不是簡單的以servlet名為Key惶傻,而是通過一些轉換,具體可自行查看源碼)其障,也將其存到ServletContext中银室,以便后續(xù)使用。這樣每個servlet就持有自己的上下文励翼,即擁有自己獨立的bean空間蜈敢,同時各個servlet共享相同的bean,即根上下文定義的那些bean汽抚。
WebapplicationServlet為Spring的根上下文或父上下文抓狭,而DispatcherServlet則為子上下文。它的主要用作職責調(diào)度工作造烁,本身主要用于控制流程否过,主要職責如下:
(1)文件上傳解析,如果請求類型是multipart將通過MultipartResolver進行文件上傳解析惭蟋;
(2)通過HandlerMapping苗桂,將請求映射到處理器(返回一個HandlerExecutionChain,它包括一個處理器告组、多個HandlerInterceptor攔截器)煤伟;
(3)通過HandlerAdapter支持多種類型的處理器(HandlerExecutionChain中的處理器);
(4)通過ViewResolver解析邏輯視圖名到具體視圖實現(xiàn);
(5)本地化解析持偏;
(6)渲染具體的視圖等驼卖;
(7)如果執(zhí)行過程中遇到異常將交給HandlerExceptionResolver來解析氨肌。
DispatcherServlet初始化的上下文加載的Bean是只對SpringMVC有效的Bean鸿秆, 如Controller、HandlerMapping怎囚、HandlerAdapter等等卿叽,該初始化上下文只加載Web相關組件。初始化完畢后恳守,spring以與servlet的名字相關(此處不是簡單的以servlet名為Key考婴,而是通過一些轉換,具體可自行查看源碼)的屬性為屬性Key催烘,也將其存到ServletContext中沥阱,以便后續(xù)使用。這樣每個servlet就持有自己的上下文伊群,即擁有自己獨立的bean空間考杉,同時各個servlet共享相同的bean,即根上下文定義的那些bean舰始。讓我們來看一個具體的DispatcherServlet的配置事例:
<servlet>
<servlet-name>qsServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/qs-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>qsServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
param-value
指定了web組件的配置文件
load-on-startup
表示啟動容器時初始化該Servlet
url-pattern
表示哪些請求交給Spring Web MVC處理崇棠, “/” 是用來定義默認servlet映射的。示例中用“*.do”表示攔截所有以do為擴展名的請求丸卷。