java web总结:servlet
一,Servlet 簡介
Java Servlet 是運行在 Web 服務器或應用服務器上的程序,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 服務器上的數據庫或應用程序之間的中間層。
使用 Servlet,您可以收集來自網頁表單的用戶輸入,呈現來自數據庫或者其他源的記錄,還可以動態創建網頁。
Java Servlet 通常情況下與使用 CGI(Common Gateway Interface,公共網關接口)實現的程序可以達到異曲同工的效果。但是相比于 CGI,Servlet 有以下幾點優勢:
1,性能明顯更好。
2,Servlet 在 Web 服務器的地址空間內執行。這樣它就沒有必要再創建一個單獨的進程來處理每個客戶端請求。
3,Servlet 是獨立于平臺的,因為它們是用 Java 編寫的。
4,服務器上的 Java 安全管理器執行了一系列限制,以保護服務器計算機上的資源。因此,Servlet 是可信的。
5,Java 類庫的全部功能對 Servlet 來說都是可用的。它可以通過 sockets 和 RMI 機制與 applets、數據庫或其他軟件進行交互。
二,Servlet的運行過程
Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求后:
①Web服務器首先檢查是否已經裝載并創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
②裝載并創建該Servlet的一個實例對象。
③調用Servlet實例對象的init()方法。
④創建一個用于封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然后調用Servlet的service()方法并將請求和響應對象作為參數傳遞進去。
⑤WEB應用程序被停止或重新啟動之前,Servlet引擎將卸載Servlet,并在卸載之前調用Servlet的destroy()方法。
1,init()方法
init 方法被設計成只調用一次。它在第一次創建 Servlet 時被調用,在后續每次用戶請求時不再調用。因此,它是用于一次性初始化。
Servlet 創建于用戶第一次調用對應于該 Servlet 的 URL 時,但是也可以指定 Servlet 在服務器第一次啟動時被加載。
當用戶調用一個 Servlet 時,就會創建一個 Servlet 實例,每一個用戶請求都會產生一個新的線程,適當的時候移交給 doGet 或 doPost 方法。init() 方法簡單地創建或加載一些數據,這些數據將被用于 Servlet 的整個生命周期。
init 方法的定義如下:
public void init() throws ServletException {// 初始化代碼... }2,service()方法
service() 方法是執行實際任務的主要方法。Servlet 容器(即 Web 服務器)調用 service() 方法來處理來自客戶端(瀏覽器)的請求,并把格式化的響應寫回給客戶端。
每次服務器接收到一個 Servlet 請求時,服務器會產生一個新的線程并調用服務。service() 方法檢查 HTTP 請求類型(GET、POST、PUT、DELETE 等),并在適當的時候調用 doGet、doPost、doPut,doDelete 等方法。
service()方法定義如下:
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException{ }service() 方法由容器調用,service 方法在適當的時候調用 doGet、doPost、doPut、doDelete 等方法。所以,您不用對 service() 方法做任何動作,只需要根據來自客戶端的請求類型來重寫 doGet() 或 doPost() 即可。
3,doGet() 方法
GET 請求來自于一個 URL 的正常請求,或者請求來自于一個特別指定了 method 為 GET的 HTML 表單,它由 doGet() 方法處理。
public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {// Servlet 代碼 }4,doPost() 方法
POST 請求來自于一個特別指定了 METHOD 為 POST 的 HTML 表單,它由 doPost() 方法處理。
public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {// Servlet 代碼 }5,destroy() 方法
destroy() 方法只會被調用一次,在 Servlet 生命周期結束時被調用。destroy() 方法可以讓您的 Servlet 關閉數據庫連接、停止后臺線程、把 Cookie 列表或點擊計數器寫入到磁盤,并執行其他類似的清理活動。
在調用 destroy() 方法之后,servlet 對象被標記為垃圾回收。
destroy 方法定義如下所示:
public void destroy() {// 終止化代碼... }三,Eclipse中開發Servlet
在eclipse中新建一個Dynamic web project工程
下一步
下一步
eclipse會自動創建下圖所示目錄結構:
創建一個HelloServlet類,繼承HttpServlet,但是報錯,這是由于沒有關聯servlet-api.jar
解決方法:
第一步:配置Tomcat服務器:Window–>Preferences–>Server–>RuntimeEnvironm–>add
選擇Apache下的Tomcat7,下一步
點擊Finish完成
完成后如圖所示,已經配置好一個Tomcat了
第二步:項目關聯剛才配置好的Tomcat服務器
右鍵單擊項目–>Preferences–>Java Build Path–>Add library
選擇Server Runtime,下一步
選擇剛才配置的Apache Tomcat v7.0,點擊Finish完成
這樣就不會報錯了。
重寫doGet,doPost方法:
修改web.xml,添加<servlet></servlet>和<servlet-mapping></servlet-mapping>兩對標簽
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><display-name>ServletDemo</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping> </web-app>四,Eclipse中運行項目
控制臺選擇Servers–>點擊如下圖紅框內容
添加New Server
把剛才創建的web項目添加到Configured,點擊Finish完成
這樣Tomcat服務器內已經部署上了ServletDemo的Web項目
右鍵單擊Tomcat v7.0–>start
如圖所示,Tomcat啟動成功
瀏覽器訪問:http://localhost:8081/ServletDemo/hello.html
五,Servlet訪問URL映射配置
由于客戶端是通過URL地址訪問web服務器中的資源,所以Servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上,這個工作在web.xml文件中使用元素和元素完成。
Servlet:該元素用于注冊Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用于設置Servlet的注冊名稱和Servlet的完整類名。
servlet-mapping:該元素用于映射一個已注冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用于指定Servlet的注冊名稱和Servlet的對外訪問路徑。
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>同一個Servlet可以被映射到多個URL上,即多個元素的子元素的設置值可以是同一個Servlet的注冊名
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello1.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello2.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>
六,ServletURL通配符:*
在Servlet映射到的URL中也可以使用*通配符,但是只能有兩種固定的格式:
格式一:*.擴展名”
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>*.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>格式二:以正斜杠(/)開頭并以”/*”結尾
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello/*</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>七,缺省Servlet
Servlet的映射路徑僅僅為一個正斜杠(/),那么這個Servlet就成為當前Web應用程序的缺省Servlet。 凡是在web.xml文件中找不到匹配的元素的URL,它們的訪問請求都將交給缺省Servlet處理。
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>八,ServletConfig
ServletConfig代表當前Servlet在web.xml中的配置信息。
1,Servlet初始化參數
在Servlet的配置文件中,可以使用一個或多個標簽為servlet配置一些初始化參數。
例如:
<servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --><init-param><param-name>name</param-name><param-value>sihai</param-value></init-param><init-param><param-name>encode</param-name><param-value>UTF-8</param-value></init-param> </servlet> <servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello.html</url-pattern><!-- servlet訪問路徑 --> </servlet-mapping>2,通過ServletConfig獲取Servlet的初始化參數
當servlet配置了初始化參數后,web容器在創建servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,并在調用servlet的init方法時,將ServletConfig對象傳遞給servlet。進而,通過ServletConfig對象就可以得到當前servlet的初始化參數信息。
public class HelloServlet extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取ServletConfigServletConfig config = this.getServletConfig();//獲取初始化參數String name = config.getInitParameter("name");String encode = config.getInitParameter("encode");//設置編碼格式,否則中文會出現亂碼resp.setCharacterEncoding("GBK");PrintWriter out = resp.getWriter();out.println("name:" + name);out.println("encode:" + encode);} }九,ServletContext
WEB容器在啟動時,它會為每個WEB應用程序都創建一個對應的ServletContext對象,它代表當前web應用。
ServletConfig對象中維護了ServletContext對象的引用,開發人員在編寫servlet時,可以通過ServletConfig.getServletContext()方法獲得ServletContext對象。
由于一個WEB應用中的所有Servlet共享同一個ServletContext對象,因此Servlet對象之間可以通過ServletContext對象來實現通訊。ServletContext對象通常也被稱之為context域對象。
1,獲取WEB應用的初始化參數
在web.xml文件中使用標簽配置WEB應用的初始化參數:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>ServletDemo</display-name><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- 配置WEB應用的初始化參數 --><context-param><param-name>name</param-name><param-value>sihai</param-value></context-param><context-param><param-name>encode</param-name><param-value>UTF-8</param-value></context-param><servlet><servlet-name>HelloServlet</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.HelloServlet</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>HelloServlet</servlet-name><url-pattern>/hello.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping> </web-app>獲取Web應用的初始化參數:
public class HelloServlet extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取ServletContextServletContext context = this.getServletContext();//獲取初始化參數String name = context.getInitParameter("name");String encode = context.getInitParameter("encode");//設置編碼格式,否則中文會出現亂碼resp.setCharacterEncoding("GBK");PrintWriter out = resp.getWriter();out.println("name:" + name);out.println("encode:" + encode);} }2,多個Servlet通過ServletContext對象實現數據共享
例如 :ServletTwo獲得ServletOne所共享的數據
ServletOne:
public class ServletOne extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//共享的數據String name = "sihai";//獲取ServletContextServletContext context = this.getServletContext();//將name存儲到ServletContext對象中context.setAttribute("name", name);} }ServletTwo:
public class ServletTwo extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取ServletContextServletContext context = this.getServletContext();//獲取初始化參數String name = (String) context.getAttribute("name");PrintWriter out = resp.getWriter();out.println("name:" + name);} }Web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>ServletDemo</display-name><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><servlet><servlet-name>ServletOne</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.ServletOne</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>ServletOne</servlet-name><url-pattern>/ServletOne.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping><servlet><servlet-name>ServletTwo</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.ServletTwo</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>ServletTwo</servlet-name><url-pattern>/ServletTwo.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping> </web-app>先訪問:http://localhost:8081/ServletDemo/ServletOne.html
再訪問:http://localhost:8081/ServletDemo/ServletTwo.html
3,用servletContext實現請求轉發
context.getRequestDispatcher()方法實現請求轉發
ServletOne:
public class ServletOne extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//共享的數據String name = "sihai";//獲取ServletContextServletContext context = this.getServletContext();//將name存儲到ServletContext對象中context.setAttribute("name", name);context.getRequestDispatcher("/ServletTwo.html").forward(req, resp);} }ServletTwo:
public class ServletTwo extends HttpServlet{private static final long serialVersionUID = 3903946972744326948L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//獲取ServletContextServletContext context = this.getServletContext();//獲取初始化參數String name = (String) context.getAttribute("name");PrintWriter out = resp.getWriter();out.println("name:" + name);} }Web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>ServletDemo</display-name><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><servlet><servlet-name>ServletOne</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.ServletOne</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>ServletOne</servlet-name><url-pattern>/ServletOne.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping><servlet><servlet-name>ServletTwo</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.ServletTwo</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>ServletTwo</servlet-name><url-pattern>/ServletTwo.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping> </web-app>訪問:http://localhost:8081/ServletDemo/ServletOne.html
訪問的是ServletOne.html,瀏覽器顯示的卻是ServletTwo.html的內容,這就是使用ServletContext實現了請求轉發。
4,利用ServletContext對象讀取資源文件
獲取上圖的config.properties資源文件內容:
GetProperties.Java:
Web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>ServletDemo</display-name><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><servlet><servlet-name>GetProperties</servlet-name><!-- servlet名稱 --><servlet-class>com.sihai.servlet.GetProperties</servlet-class><!-- servlet關聯的類 --></servlet><servlet-mapping><servlet-name>GetProperties</servlet-name><url-pattern>/GetProperties.html</url-pattern><!-- servlet訪問路徑 --></servlet-mapping> </web-app>訪問路徑:http://localhost:8081/ServletDemo/GetProperties.html
十、Servlet的線程安全問題
當多個客戶端并發訪問同一個Servlet時,web服務器會為每一個客戶端的訪問請求創建一個線程,并在這個線程上調用Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題。例如下面的代碼:
不存在線程安全問題的代碼:
package sihai.servlet.study;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {/*** 當多線程并發訪問這個方法里面的代碼時,會存在線程安全問題嗎* i變量被多個線程并發訪問,但是沒有線程安全問題,因為i是doGet方法里面的局部變量,* 當有多個線程并發訪問doGet方法時,每一個線程里面都有自己的i變量,* 各個線程操作的都是自己的i變量,所以不存在線程安全問題* 多線程并發訪問某一個方法的時候,如果在方法內部定義了一些資源(變量,集合等)* 那么每一個線程都有這些東西,所以就不存在線程安全問題了*/int i=1;i++;response.getWriter().write(i);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}存在線程安全問題的代碼:
package sihai.servlet.study;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet {int i=1;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {i++;try {Thread.sleep(1000*4);} catch (InterruptedException e) {e.printStackTrace();}response.getWriter().write(i+"");}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}把i定義成全局變量,當多個線程并發訪問變量i時,就會存在線程安全問題了,如下圖所示:同時開啟兩個瀏覽器模擬并發訪問同一個Servlet,本來正常來說,第一個瀏覽器應該看到2,而第二個瀏覽器應該看到3的,結果兩個瀏覽器都看到了3,這就不正常。
線程安全問題只存在多個線程并發操作同一個資源的情況下,所以在編寫Servlet的時候,如果并發訪問某一個資源(變量,集合等),就會存在線程安全問題,那么該如何解決這個問題呢?
先看看下面的代碼:
package sihai.servlet.study;import java.io.IOException;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;public class ServletDemo3 extends HttpServlet {int i=1;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {/*** 加了synchronized后,并發訪問i時就不存在線程安全問題了,* 為什么加了synchronized后就沒有線程安全問題了呢?* 假如現在有一個線程訪問Servlet對象,那么它就先拿到了Servlet對象的那把鎖* 等到它執行完之后才會把鎖還給Servlet對象,由于是它先拿到了Servlet對象的那把鎖,* 所以當有別的線程來訪問這個Servlet對象時,由于鎖已經被之前的線程拿走了,后面的線程只能排隊等候了* */synchronized (this) {//在java中,每一個對象都有一把鎖,這里的this指的就是Servlet對象i++;try {Thread.sleep(1000*4);} catch (InterruptedException e) {e.printStackTrace();}response.getWriter().write(i+"");}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}現在這種做法是給Servlet對象加了一把鎖,保證任何時候都只有一個線程在訪問該Servlet對象里面的資源,這樣就不存在線程安全問題了
這種做法雖然解決了線程安全問題,但是編寫Servlet卻萬萬不能用這種方式處理線程安全問題,假如有9999個人同時訪問這個Servlet,那么這9999個人必須按先后順序排隊輪流訪問。
針對Servlet的線程安全問題,Sun公司是提供有解決方案的:讓Servlet去實現一個SingleThreadModel接口,如果某個Servlet實現了SingleThreadModel接口,那么Servlet引擎將以單線程模式來調用其service方法。
查看Sevlet的API可以看到,SingleThreadModel接口中沒有定義任何方法和常量,在Java中,把沒有定義任何方法和常量的接口稱之為標記接口,經常看到的一個最典型的標記接口就是”Serializable”,這個接口也是沒有定義任何方法和常量的,標記接口在Java中有什么用呢?主要作用就是給某個對象打上一個標志,告訴JVM,這個對象可以做什么,比如實現了”Serializable”接口的類的對象就可以被序列化,還有一個”Cloneable”接口,這個也是一個標記接口,在默認情況下,Java中的對象是不允許被克隆的,就像現實生活中的人一樣,不允許克隆,但是只要實現了”Cloneable”接口,那么對象就可以被克隆了。
讓Servlet實現了SingleThreadModel接口,只要在Servlet類的定義中增加實現SingleThreadModel接口的聲明即可。
對于實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程并發訪問,其采用的方式是產生多個Servlet實例對象,并發的每個線程分別調用一個獨立的Servlet實例對象。
實現SingleThreadModel接口并不能真正解決Servlet的線程安全問題,因為Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記為Deprecated(過時的)。
總結
以上是生活随笔為你收集整理的java web总结:servlet的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java web总结:tomcat使用教
- 下一篇: tomcat基本使用,就是这么简单