於 Web 容器來說,Servlet 的基本行為,規範在 Servlet
介面中:
package javax.servlet;
import java.io.IOException;
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
當一個實作 Servlet
介面的類別被容器載入之後,容器會建立該類別的實例,根據 Servlet 設定資訊(定義在標註或 web.xml)建立實作 ServletConfig
介面的實例(之後再介紹 ServletConfig
介面),呼叫 Servlet
的 init()
方法並傳入 ServletConfig
實例完成 Servlet 的初始化。
在完成 Servlet 初始化後,如果有請求將由某個 Servlet 處理,則容器會呼叫該 Servlet
的 service()
方法,傳入 ServletRequest
、ServletResponse
實例,注意這兩個介面並非以 Http 名稱作開頭,ServletRequest
、ServletResponse
的套件亦是 javax.servlet
,這是由於最初設計Servlet時,並不限定它只能用在 HTTP 上(雖然最後 Servlet 還是只有 HTTP 上的實現)。
當一個 Servlet
實例不被容器管理前,容器會呼叫它的 destroy()
方法,以執行一些資源回收的動作。
實作 Servlet
介面的類別是 GenericServlet
類別,這是一個抽象類別:
package javax.servlet;
import java.io.IOException;
import java.util.Enumeration;
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
}
@Override
public void destroy() {
}
@Override
public String getInitParameter(String name) {
return getServletConfig().getInitParameter(name);
}
@Override
public Enumeration<String> getInitParameterNames() {
return getServletConfig().getInitParameterNames();
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
}
@Override
public String getServletInfo() {
return "";
}
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String msg) {
getServletContext().log(getServletName() + ": " + msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
@Override
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
@Override
public String getServletName() {
return config.getServletName();
}
}
GenericServlet
實作了 Servlet
介面,其中接受 ServletConfig
的 init()
方法,會將傳入的 ServletConfig
實例設定給類別成員 config
,之後呼叫無參數的 init()
方法,所以若你要定義 Servlet
的初始化,不建議直接重新定義接受 ServletConfig
的 init()
方法,而是重新定義無參數的 init()
方法。
GenericServlet
對 Servlet
介面的 service()
方法沒有實作,僅標示為 abstract
,service()
方法的實作由子類別 HttpServlet
來完成:
package javax.servlet.http;
略...
public abstract class HttpServlet extends GenericServlet {
public HttpServlet() {}
略...
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
略...
}
略...
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
}
HttpServlet
是基於 HTTP 服務的一個類別,注意其套件是 javax.servlet.http
,它實作了 GenericServlet
未實作的 service()
方法,如果是在 Web 容器,實作上傳入的請求、回應物件是實作 HttpServletRequest
、HttpServletResponse
介面,它們分別是 ServletRequest
、ServletResponse
的子介面,增加了一些 HTTP 相關操作的行為,HttpServletRequest
、 HttpServletResponse
的套件亦歸類在 javax.servlet.http
。
HttpServlet
實作了 GenericServlet
未實作的 service()
方法,將傳入的 ServletRequest
、ServletResponse
轉換為 HttpServletRequest
、HttpServletResponse
,並呼叫自己定義的、接受 HttpServletRequest
、HttpServletResponse
作為參數的 service()
方法,在這個 service()
方法中,根據 HTTP 請求方式,決定該呼叫 doGet()
、doPost()
等方法。你可以參考〈只有 doGet()、doPost()〉的內容。