Servlet的生命週期、工作原理和一次請求響應過程
一、Servlet的生命週期
Servlet的生命週期分為4個階段:例項化- ->初始化- ->執行處理- ->銷燬
(1)例項化——new:伺服器第一次被訪問時,載入一個Servlet容器,而且只會被載入一次。
(2)初始化——init:建立完Servlet容器後,會呼叫僅執行一次的init()初始化方法,用於初始化Servlet物件,無論多少臺客戶端在伺服器執行期間訪問都不會再執行init()方法。
可以在繼承的GenericServlet這個抽象類中看到初始化方法:
public void init() throws ServletException {
}
而在我們的Servlet類中應繼承呼叫該方法:
public void init() throws ServletException {
super.init();
}
(3)執行處理——service()方法:HttpServlet的抽象類提供了doGet()、doPost()……等方法。對應了request請求的傳送方法,與之相匹配:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported" );
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported" );
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
(4)銷燬——destroy:在伺服器關閉或重啟時,Servlet會呼叫destroy方法來銷燬,將Servlet容器標記為垃圾檔案,讓GC做回收處理。我們編寫的Servlet是呼叫了GenericServlet抽象類的destroy方法:
@Override
public void destroy() {
super.destroy();
}
二、Servlet的工作原理
1、首先簡單解釋一下Servlet接收和響應客戶請求的過程:
客戶傳送一個請求,Servlet是呼叫service()方法對請求進行響應的,通過原始碼可見,service()方法中對請求的方式進行了匹配。選擇呼叫doGet,doPost等這些方法,然後再進入對應的方法中呼叫邏輯層的方法,實現對客戶的響應。在Servlet介面和GenericServlet中是沒有doGet()、doPost()等等這些方法的,HttpServlet中定義了這些方法,但是都是返回error資訊,所以,我們每次定義一個Servlet的時候,都必須實現doGet或doPost等這些方法。
2、每一個自定義的Servlet都必須實現Servlet的介面,Servlet介面中定義了五個方法,其中比較重要的三個方法涉及到Servlet的生命週期,分別是上文提到的init(),service(),destroy()方法。GenericServlet是一個通用的,不特定於任何協議的Servlet,它實現了Servlet介面。而HttpServlet繼承於GenericServlet,因此HttpServlet也實現了Servlet介面。所以我們定義Servlet的時候只需要繼承HttpServlet即可。
package javax.servlet;
import java.io.IOException;
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
3、Servlet介面和GenericServlet是不特定於任何協議的,而HttpServlet是特定於HTTP協議的類,所以HttpServlet中實現了service()方法,並將請求ServletRequest、ServletResponse 強轉為HttpRequest 和 HttpResponse。
以上三點參考:Servlet的工作原理
4、另外,Servlet是單例模式,執行緒是不安全的,因此在service()方法中儘量不要操作全域性變數。但實際上,可以通過使用session和application來代替全域性變數,只是會加大伺服器負載。
三、Servlet處理請求的過程
- 客戶端傳送請求給伺服器。
- 容器根據請求及web.xml判斷對應的Servlet是否存在,如果不存在則返回404
- 容器根據請求及web.xml判斷對應的Servlet是否已經被例項化,若是相應的Servlet沒有被例項化,則容器將會載入相應的Servlet到Java虛擬機器並例項化
- 呼叫例項物件的service()方法,並開啟一個新的執行緒去執行相關處理。呼叫servce方法,判斷是呼叫doGet方法還是doPost方法
- 業務完成後響應相關的頁面傳送給客戶端。