ServletContext是一個全局的儲存信息的空間,服務(wù)器開始就存在,服務(wù)器關(guān)閉才釋放。為了方便大家理解,我們將ServletContext和Cookie、Session做一個簡單對比,如下圖:
我們可以把ServletContext當(dāng)成一個公用的空間,可以被所有的客戶訪問,如上圖,A、B、C三個客戶端都可以訪問。
WEB容器在啟動時,它會為每個Web應(yīng)用程序都創(chuàng)建一個對應(yīng)的ServletContext,它代表當(dāng)前Web應(yīng)用,并且它被所有客戶端共享。
由于一個WEB應(yīng)用中的所有Servlet共享同一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現(xiàn)通訊。ServletContext對象通常也被稱之為context域?qū)ο?。公共聊天室就會用到它?/p>
當(dāng)web應(yīng)用關(guān)閉、Tomcat關(guān)閉或者Web應(yīng)用reload的時候,ServletContext對象會被銷毀
ServletContext使用方法
1、ServletContext對象如何得到
this.getServletContext();
this.getServletConfig().getServletContext();
2、你可以把它想象成一張表,這個和Session非常相似:每一行就是一個屬性,如下:
名字(String) | 值(Object) |
---|---|
|
添加屬性:setAttribute(String name, Object obj);
得到值:getAttribute(String name),這個方法返回Object
刪除屬性:removeAttribute(String name)
3、生命周期
ServletContext中的屬性的生命周期從創(chuàng)建開始,到服務(wù)器關(guān)閉結(jié)束。
一個快速入門的案例:
我們創(chuàng)建Servlet1和Servlet2,分別用于在ServletContext中創(chuàng)建和讀取屬性:
Servlet1的doGet方法為:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 獲取ServletContext對象的引用
// 第一種方法
ServletContext servletContext = this.getServletContext();
// 第二種方法
// ServletContext servletContext2 = this.getServletConfig().getServletContext();
servletContext.setAttribute("name", "小明");
out.println("將 name=小明 寫入了ServletContext");
}
Servlet2的doGet方法為:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 取出ServletContext的某個屬性
//1.首先獲取到ServletContext
ServletContext servletContext = this.getServletContext();
//2.取出屬性
String name = (String)servletContext.getAttribute("name");
out.println("name="+name);
}
以此訪問Servlet1和Servlet2,我們可以分別看到輸出如下:
粗看之下,這個運行結(jié)果和Session,Cookie的應(yīng)用似乎沒什么區(qū)別,但事實上則完全不一樣的。只要不關(guān)閉Tomcat或者reload該應(yīng)用,當(dāng)我們關(guān)閉當(dāng)前的瀏覽器,或者是換一個瀏覽器,比如從360瀏覽器換到了IE瀏覽器再次訪問Servlet2,我們依然可以看到這個結(jié)果!這就是和和Session,Cookie最大的不同了。之所以會造成這種不同,是因為ServletContext存在于服務(wù)器內(nèi)存中的一個公共空間,它可以供所有的用戶客戶端訪問。
ServletContext應(yīng)用
1、多個Servlet可以通過ServletContext對象來實現(xiàn)數(shù)據(jù)間的共享
類似于Session,通過ServletContext對象我們也可以實現(xiàn)數(shù)據(jù)共享,但值得注意的是,Session是只能在一個客戶端中共享數(shù)據(jù),而ServletContext中的數(shù)據(jù)是在所有客戶端中都可以實現(xiàn)數(shù)據(jù)共享的。
2、實現(xiàn)Servlet的請求轉(zhuǎn)發(fā)
之前我們學(xué)過的請求轉(zhuǎn)發(fā)是通過request對象的:
request.getRequestDispatcher("/url").forward(request, response);
這里要說明的是,ServletContext也可以實現(xiàn)請求轉(zhuǎn)發(fā):
this.getServletContext().getRequestDispatcher("/url").forward(request, response);
這兩個轉(zhuǎn)發(fā)效果是一樣的。
3、獲取Web應(yīng)用的初始化參數(shù)
我們可以用<init-param>標(biāo)簽為servlet配置初始化參數(shù),然后使用ServletConfig對象獲取這些參數(shù),假如有如下的MyServlet,它的配置為:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.gavin.servlet.MyServlet</servlet-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
可以看到它配置了一個初始化參數(shù):encoding=utf-8,那么我們在MyServlet的源代碼中需要這樣去得到這個參數(shù):
String encoding = this.getServletConfig().getInitParameter("encoding");
注意,上述的參數(shù)配置方法只針對一個特定的Servlet有效,我們可以通過ServletContext來獲取全局的、整個Web應(yīng)用的初始化參數(shù),全局的初始化參數(shù)是這樣配置在web.xml文件中的:
<!-- 如果希望所有的Servlet都可以使用該配置,則必須這么做 -->
<context-param>
<param-name>name</param-name>
<param-value>gavin</param-value>
</context-param>
然后我們可以在任意一個Servlet中使用ServletContext獲取這個參數(shù):
String name = this.getServletContext().getInitParameter("name");
4、利用ServletContext對象讀取資源文件(比如properties文件)
讀取資源文件要根據(jù)資源文件所在的位置來決定,一般分為以下兩種情況:
4.1:文件在WebRoot文件夾下,即Web應(yīng)用的根目錄。這時候我們可以使用ServletContext來讀取該資源文件。
假設(shè)我們Web根目錄下有一個配置數(shù)據(jù)庫信息的dbinfo.properties文件,里面配置了name和password屬性,這時候可以通過ServletContext去讀取這個文件:
// 這種方法的默認(rèn)讀取路徑就是Web應(yīng)用的根目錄
InputStream stream = this.getServletContext().getResourceAsStream("dbinfo.properties");
// 創(chuàng)建屬性對象
Properties properties = new Properties();
properties.load(stream);
String name = properties.getProperty("name");
String password = properties.getProperty("password");
out.println("name="+name+";password="+password);
4.2:如果這個文件放在了src目錄下,這時就不能用ServletContext來讀取了,必須要使用類加載器去讀取。
// 類加載器的默認(rèn)讀取路徑是src根目錄
InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("dbinfo.properties")
如果這個文件此時還沒有直接在src目錄下,而是在src目錄下的某個包下,比如在com.gavin包下,此時類加載器要加上包的路徑,如下:
InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("com/gavin/dbinfo.properties")
補充一點,ServletContext只有在讀取的文件在web應(yīng)用的根目錄下時,才能獲取文件的全路徑。比如我們在WebRoot文件夾下有一個images文件夾,images文件夾下有一個Servlet.jpg圖片,為了得到這個圖片的全路徑,如下:
// 如何讀取到一個文件的全路徑,這里會得到在Tomcat的全路徑
String path = this.getServletContext().getRealPath("/images/Servlet.jpg");
在網(wǎng)站開發(fā)中,有很多功能要使用ServletContext,比如
1. 網(wǎng)站計數(shù)器
2. 網(wǎng)站的在線用戶顯示
3. 簡單的聊天系統(tǒng)
總之,如果是涉及到不同用戶共享數(shù)據(jù),而這些數(shù)據(jù)量不大,同時又不希望寫入數(shù)據(jù)庫中,我們就可以考慮使用ServletContext實現(xiàn)。
ServletContext使用建議
因為存在ServletContext中的數(shù)據(jù)在服務(wù)器中會長時間,這樣就會占用很多內(nèi)存,因此在使用ServletContext時,建議不要往里面添加過大的數(shù)據(jù)!
相關(guān)閱讀:
更多建議: