1. 程式人生 > >Servlet的執行原理

Servlet的執行原理

一:servlet定義

Servlet是一個Java應用程式,執行在伺服器端,用來處理客戶端請求並作出響應的程式。

Servlet多執行緒體系結構是建立在Java多執行緒機制之上的,它的生命週期是由Web容器負責的。

      當客戶端第一次請求某個Servlet時,Servlet容器將會根據web.xml配置檔案例項化這個Servlet類,此時它貯存於記憶體中。。當有新的客戶端請求該Servlet時,一般不會再例項化該Servlet類,也就是有多個執行緒在使用這個例項。 這樣,當兩個或多個執行緒同時訪問同一個Servlet時,可能會發生多個執行緒同時訪問同一資源的情況,資料可能會變得不一致。所以在用Servlet構建的Web應用時要注意執行緒安全的問題。每一個請求都是一個執行緒,而不是程序,因此,Servlet對請求的處理的效能非常高。

        對於Servlet,它被設計為多執行緒的(如果它是單執行緒的,你就可以想象,當1000個人同時請求一個網頁時,在第一個人獲得請求結果之前,其它999個人都在鬱悶地等待),如果為每個使用者的每一次請求都建立 一個新的執行緒物件來執行的話,系統就會在建立執行緒和銷燬執行緒上耗費很大的開銷,大大降低系統的效率。

因此,Servlet多執行緒機制背後有一個執行緒池在支援,執行緒池在初始化初期就建立了一定數量的執行緒物件,通過提高對這些物件的利用率,避免高頻率地建立物件,從而達到提高程式的效率的目的。(由執行緒來執行Servlet的service方法,servlet在Tomcat中是以單例模式存在的, Servlet的執行緒安全問題只有在大量的併發訪問時才會顯現出來,並且很難發現,因此在編寫Servlet程式時要特別注意。執行緒安全問題主要是由例項變數造成的,因此在Servlet中應避免使用例項變數。如果應用程設計無法避免使用例項變數,那麼使用同步來保護要使用的例項變數,但為保證系統的最佳效能,應該同步可用性最小的程式碼路徑)

 Struts2的Action是原型,非單例項的;會對每一個請求,產生一個Action的例項來處理。

          解決servlet執行緒安全的方案:同步對共享資料的操作 Synchronized (this){...}、避免使用例項變數

①客戶端向伺服器端發出請求;

②這個過程比較重要,這時Tomcat會建立兩個物件:HttpServletResponse和HttpServletRequest。並將它們的引用(注意是引用)傳給剛分配的執行緒;

③執行緒開始著手接洽servlet;

④servlet根據傳來的是GET和POST,分別呼叫doGet()和doPost()方法進行處理;

⑤和⑥servlet將處理後的結果通過執行緒傳回Tomcat,並在之後將這個執行緒銷燬或者送還執行緒池;

⑦Tomcat將處理後的結果變成一個HTTP響應傳送回客戶端,這樣,客戶端就可以接受到處理後的結果了。

二:簡單servlet例項 

//匯入所需的包

import javax.servlet.http.*;

import javax.servlet.*;

import java.io.*;

public class FirstServlet extends HttpServlet {

//處理請求的方法

public void doGet(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, java.io.IOException {

//資料傳送給客戶端—>控制檯方式輸出

//System.out.println(“Hello Servlet”);

//資料傳送給客戶端—>HTML頁面輸出

resp.setContentType(“text/html”);

resp.getWriter().print(“<html>”);

resp.getWriter().print(“<head>”);

resp.getWriter().print(“</head>”);

resp.getWriter().print(“<body>”);

resp.getWriter().print(“Hello World”);

resp.getWriter().print(“</body>”);

resp.getWriter().print(“</html>”);

}

}

三:servlet配置到Tomcat中去

Tomcat是一個web容器,也叫web伺服器。我們都知道J2EE有十三個標準,這些標準大部分都是介面,Tomcat只是實現了JSP 和 servlet 開發標準。實現了所有的開發標準,就是應用程式伺服器,比如Jboss。

編譯好的servlet類只能執行在tomcat容器中,客戶端瀏覽器不可以直接訪問Servlet,需要在web.xml中配置一下 

<servlet>

<servlet-name>FirstServlet</servlet-name>

<servlet-class>FirstServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>FirstServlet</servlet-name>

<url-pattern>/servlet/FirstServlet</url-pattern>

</servlet-mapping>

四:servlet執行原理

1. WebApplication的標準目錄結構:

WEB-INF/classes

/lib

Web.xml

也就是一個完整的web應用程式目錄下,必須包含以上的目錄結構。

Classes 資料夾下是專案中用到的類檔案,均由JDK編譯成了.class檔案

Lib資料夾是我們專案中引用的jar包

Web.xml是整個web應用程式的配置文件。

瞭解了這些,我們再來看Tomcat的工作流程。

2. Tomcat解析URL

a) 首先來看URL中包含的資訊:”協議” + “埠號” + “路徑(專案名稱+檔案路徑)”

Tomcat啟動後,監聽我們的8080埠,當有Url請求發過來之後,解析出專案名稱 abingtest,然後到webapps目錄下搜尋到該專案資料夾。

b) 專案檔案找到後,開始尋找類檔案。

這個時候Tomcat去Web.xml檔案中尋找<servlet-mapping> 配置節中包含”servlet/FirstServlet”字串,進而找到該類檔案所在的位置。 

3. Servelt中的doGet() 和 doPost() 方法

我們寫的FirstServlet 繼承了HttpServlet ,重寫了HttpServlet中的doGet() 方法,HttpServlet中還有一個doPost()方法。這兩個方法都是用來處理Http請求的。Servlet會根據我們提交表單的方法(method=post/get)呼叫service方法來自動選擇(我們在下一篇文章中來詳細說明一下Service方法是如何自動呼叫FirstServlet中的doGet()方法的)

4. Servlet如何接收資料

import javax.servlet.http.*;

import javax.servlet.*;

import java.io.*;

public class FirstServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, java.io.IOException {

//獲取表單資料

String userName = request.getParameter(“userName”);

}

}

 Http協議會將網頁中的所有內容包裝成為一個request物件傳遞給servlet ,Servlet通過這個物件拿到表單中的所有資料,處理完成之後,通過Response物件返回給客戶端瀏覽器。

5. Servlet的生命週期

Servlet的生命週期是由Tomcat容器管理的

a) 客戶發出請求—>Web 伺服器轉發到Web容器Tomcat;

b) Tomcat主執行緒對轉發來使用者的請求做出響應建立兩個物件:HttpServletRequest和HttpServletResponse;

c) 從請求中的URL中找到正確Servlet,Tomcat為其建立或者分配一個執行緒,同時把2建立的兩個物件傳遞給該執行緒;

d) Tomcat呼叫Servlet的servic()方法,根據請求引數的不同調用doGet()或者doPost()方法;

e) 假設是HTTP GET請求,doGet()方法生成靜態頁面,並組合到響應物件裡;
Servlet執行緒結束,Tomcat將響應物件轉換為HTTP響應發回給客戶,同時刪除請求和響應物件。
從該過程中,我們可以理解Servlet的生命週期:Servlet類載入(對應3步);Servlet例項化(對應3步);呼叫init方法(對應3步);呼叫service()方法(對應4、5步);;呼叫destroy()方法(對應6步)。

五:Servlet生命週期的各個階段

Servlet執行在Servlet容器中,其生命週期由容器來管理。Servlet的生命週期通過javax.servlet.Servlet介面中的init()、service()和destroy()方法來表示。

Servlet的生命週期包含了下面4個階段: 

(1)載入和例項化

Servlet容器負責載入和例項化Servlet。當Servlet容器啟動時,或者在容器檢測到需要這個Servlet來響應第一個請求時,建立Servlet例項。當Servlet容器啟動後,它必須要知道所需的Servlet類在什麼位置,Servlet容器可以從本地檔案系統、遠端檔案系統或者其他的網路服務中通過類載入器載入Servlet類,成功載入後,容器建立Servlet的例項。因為容器是通過Java的反射API來建立Servlet例項,呼叫的是Servlet的預設構造方法(即不帶引數的構造方法),所以我們在編寫Servlet類的時候,不應該提供帶引數的構造方法。

(2)初始化

在Servlet例項化之後,容器將呼叫Servlet的init()方法初始化這個物件。初始化的目的是為了讓Servlet物件在處理客戶端請求前完成一些初始化的工作,如建立資料庫的連線,獲取配置資訊等。對於每一個Servlet例項,init()方法只被呼叫一次。在初始化期間,Servlet例項可以使用容器為它準備的ServletConfig物件從Web應用程式的配置資訊(在web.xml中配置)中獲取初始化的引數資訊。在初始化期間,如果發生錯誤,Servlet例項可以丟擲ServletException異常或者UnavailableException異常來通知容器。ServletException異常用於指明一般的初始化失敗,例如沒有找到初始化引數;而UnavailableException異常用於通知容器該Servlet例項不可用。例如,資料庫伺服器沒有啟動,資料庫連線無法建立,Servlet就可以丟擲UnavailableException異常向容器指出它暫時或永久不可用。

(3)請求處理

Servlet容器呼叫Servlet的service()方法對請求進行處理。要注意的是,在service()方法呼叫之前,init()方法必須成功執行。在service()方法中,Servlet例項通過ServletRequest物件得到客戶端的相關資訊和請求資訊,在對請求進行處理後,呼叫ServletResponse物件的方法設定響應資訊。在service()方法執行期間,如果發生錯誤,Servlet例項可以丟擲ServletException異常或者UnavailableException異常。如果UnavailableException異常指示了該例項永久不可用,Servlet容器將呼叫例項的destroy()方法,釋放該例項。此後對該例項的任何請求,都將收到容器傳送的HTTP 404(請求的資源不可用)響應。如果UnavailableException異常指示了該例項暫時不可用,那麼在暫時不可用的時間段內,對該例項的任何請求,都將收到容器傳送的HTTP 503(伺服器暫時忙,不能處理請求)響應。

(4)服務終止

當容器檢測到一個Servlet例項應該從服務中被移除的時候,容器就會呼叫例項的destroy()方法,以便讓該例項可以釋放它所使用的資源,儲存資料到持久儲存裝置中。當需要釋放記憶體或者容器關閉時,容器就會呼叫Servlet例項的destroy()方法。在destroy()方法呼叫之後,容器會釋放這個Servlet例項,該例項隨後會被Java的垃圾收集器所回收。如果再次需要這個Servlet處理請求,Servlet容器會建立一個新的Servlet例項。

在整個Servlet的生命週期過程中,建立Servlet例項、呼叫例項的init()和destroy()方法都只進行一次,當初始化完成後,Servlet容器會將該例項儲存在記憶體中,通過呼叫它的service()方法,為接收到的請求服務。下面給出Servlet整個生命週期過程的UML序列圖 

轉載於:http://www.cnblogs.com/gaoxiangde/p/4339571.html