日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java web总结:servlet

發布時間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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方法:

import java.io.IOException; import java.io.PrintWriter;import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;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 {//設置編碼格式,否則中文會出現亂碼resp.setCharacterEncoding("GBK");PrintWriter out = resp.getWriter();out.println("Hello Servlet!");out.println("你好 Servlet!");} }

修改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:

public class GetProperties 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 {//設置瀏覽器編碼格式為UTF-8resp.setHeader("content-type","text/html;charset=UTF-8");resp.getWriter().println("讀取src目錄下的config.properties配置文件:");//讀取src目錄下的properties配置文件readProperties(resp,"/WEB-INF/classes/config.properties");resp.getWriter().println("<hr/>讀取WebRoot目錄下的config.properties配置文件:");//讀取WebRoot目錄下的properties配置文件readProperties(resp,"config.properties");}/*** * @方法名: readProperties* @描述: 獲取properties配置文件內容* @param resp* @param fileUrl* @throws IOException * @創建人 sihai*/protected void readProperties(HttpServletResponse resp, String fileUrl) throws IOException{//2種方式都能獲取到config.properties//InputStream in = new FileInputStream(this.getServletContext().getRealPath(fileUrl));InputStream in = this.getServletContext().getResourceAsStream(fileUrl);Properties prop = new Properties();prop.load(in);String url = prop.getProperty("database.url");String username = prop.getProperty("database.username");String password = prop.getProperty("database.password");resp.getWriter().println(MessageFormat.format("url={0},username={1},password={2}", url,username, password));} }

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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。