實驗說明Servlet的生命週期
Servlet的生命週期
Servlet是執行在伺服器端的程式,它的執行狀態由Servlet容器(簡稱容器)來維護。
通常,在容器收到客戶對Servlet的請求時,容器會判斷這個Servlet是否為第一次被訪問,如果是第一次被訪問,則會建立一個Servlet例項同時呼叫該例項的init()方法,進行初始化。
每個Servlet只會被建立一個例項,同時也只會被初始化一次。然後將這個例項一直儲存在記憶體中,對所有的請求進行處理。預設的服務功能是呼叫與HTTP請求方法相應的do功能。同時,HttpServlet.service()方法會檢查請求方法是否呼叫了適當的處理方法。
最後,當伺服器關閉時,容器將會呼叫Servlet的destroy()方法清除Servlet例項。
我們下面用實驗看一下這個過程:
實驗驗證
首先,我們寫一個很簡單的JSP程式,我們通過JSP頁面來呼叫Servlet方法。我們在Tomcat安裝目錄下的webapps資料夾下新建一個ServletLife資料夾,進入該資料夾,寫一個index.jsp檔案,程式碼如下:
index.jsp
<%@ page contentType="text/html;charset=GBK" language="java" %>
<html>
<head>
<title>Show servlet life cycle</title >
</head>
<body>
<center>
<form action="ShowLifeCycle" name=form">
<input type="submit" value="SUBMIT"></form>
</center>
</body>
</html>
這是一段很簡單的JSP程式,只為說明問題,整個程式只有一個提交表單的”submit”。
- 程式碼第8行指定表單提交給ShowLifeCycle
- 程式碼第9行建立一個“提交”
然後我們在我們建立的/ServletLife目錄下新建一個WEB-INF資料夾,進入WEB-INF資料夾,再建立一個classes資料夾。
接下來,建立Servlet.java,程式碼如下:
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
public class Servlet extends HttpServlet {
private ServletConfig config;
private static int counter = 0;
public Servlet() {
super();
System.out.println("=== " + ++counter + " instances ===");
}
//初始化servlet
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.config = config;
System.out.println("=== invoke init() ===" + new Date().toString());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("=== invoke doPost ===" + new Date().toString());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("=== invoke doGet() ===" + new Date().toString());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
System.out.println("=== invoke service ===");
}
@Override
public void destroy() {
System.out.println("=== invoke destroy() ===" + new Date().toString());
}
}
- 11行,定義一個類變數,用來記錄一共建立了幾個例項。
- 13~16行,顯式地寫出建構函式,是為了打印出一共建立了多少個例項。
- 18~24行,初始化函式。每次呼叫顯示”=== invoke init() ===”以及當前時間。
- 26~28行,在doPost()方法中列印”=== invoke doPost ===”以及當前時間。
- 30~32行,在doGet()方法中列印”=== invoke doGet ===”以及當前時間。
- 34~38行,這裡我們重寫service()方法,只是為了在呼叫此方法的時候打印出””’ invoke service ===”以及當前時間。
- 40~43行,在呼叫destroy()方法時,列印”=== invoke destroy() ===”以及當前時間。
將該java檔案編譯後的Servlet.class放到/WEB-INF/classes資料夾下。
然後在/WEB-INF資料夾下建立一個配置檔案web.xml:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>LifeCycle</servlet-name>
<servlet-class>Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeCycle</servlet-name>
<url-pattern>/ShowLifeCycle</url-pattern>
</servlet-mapping>
</web-app>
這個檔案主要來配置Servlet的。
接下來執行Tomcat,我們在Tomcat安裝目錄下的logs資料夾中找到剛剛生成(看修改日期的時間)的tomcat7-stdout.2016-03-15文字文件檔案,裡面會有一行剛剛列印的文字:
2016-03-15 20:04:53 Commons Daemon procrun stdout initialized
此時伺服器正常啟動。
然後我們在瀏覽器位址列輸入
localhost/8080/http://localhost:8080/ServletLife/index.jsp
只有一個submit按鈕:
點選該按鈕,此時Servlet被請求,關閉重新開啟剛才的tomcat7-stdout.2016-03-15,此時內容如下:
2016-03-15 20:04:53 Commons Daemon procrun stdout initialized
=== 1 instances ===
=== invoke init() ===Tue Mar 15 20:10:20 CST 2016
=== invoke doGet() ===Tue Mar 15 20:10:20 CST 2016
=== invoke service ===
- 第2行,當第一次收到該Servlet請求時,會呼叫該Servlet的例項方法,並建立1個例項。”=== 1 instances ===”;
- 第3行,建立該例項後,呼叫Servlet的init()方法進行初始化操作;
- 第4行,通過doGet()方法處理請求響應;
- 第5行,在service()方法最後一行打印出”=== invoke service ===”,實際上,doGet()方法是由service()方法呼叫的。
接下來我們重新建立一個Servlet請求,開啟瀏覽器,重複以上過程,找到localhost/8080/ServletLife/index.jsp
頁面,點選submit,然後重新開啟剛才的文字文件,內容如下:
2016-03-15 20:04:53 Commons Daemon procrun stdout initialized
=== 1 instances ===
=== invoke init() ===Tue Mar 15 20:10:20 CST 2016
=== invoke doGet() ===Tue Mar 15 20:10:20 CST 2016
=== invoke service ===
=== invoke doGet() ===Tue Mar 15 20:18:50 CST 2016
=== invoke service ===
新增加了6、7兩行。再次請求Servlet,並沒有新建一個Servlet例項,也沒有init過程,直接使用上次建立的例項來處理請求響應,doGet()方法被呼叫。
然後我們關閉Tomcat伺服器。重新開啟以上文字文件,內容如下:
2016-03-15 20:04:53 Commons Daemon procrun stdout initialized
=== 1 instances ===
=== invoke init() ===Tue Mar 15 20:10:20 CST 2016
=== invoke doGet() ===Tue Mar 15 20:10:20 CST 2016
=== invoke service ===
=== invoke doGet() ===Tue Mar 15 20:18:50 CST 2016
=== invoke service ===
=== invoke destroy() ===Tue Mar 15 20:22:43 CST 2016
destroy()方法被呼叫,清除Servlet例項。