Servlet、GenericServlet、HttpServlet


於 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 介面),呼叫 Servletinit() 方法並傳入 ServletConfig 實例完成 Servlet 的初始化。

在完成 Servlet 初始化後,如果有請求將由某個 Servlet 處理,則容器會呼叫該 Servletservice() 方法,傳入 ServletRequestServletResponse 實例,注意這兩個介面並非以 Http 名稱作開頭,ServletRequestServletResponse 的套件亦是 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 介面,其中接受 ServletConfiginit() 方法,會將傳入的 ServletConfig 實例設定給類別成員 config,之後呼叫無參數的 init() 方法,所以若你要定義 Servlet 的初始化,不建議直接重新定義接受 ServletConfiginit() 方法,而是重新定義無參數的 init() 方法。

GenericServletServlet 介面的 service() 方法沒有實作,僅標示為 abstractservice() 方法的實作由子類別 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 容器,實作上傳入的請求、回應物件是實作 HttpServletRequestHttpServletResponse 介面,它們分別是 ServletRequestServletResponse 的子介面,增加了一些 HTTP 相關操作的行為,HttpServletRequestHttpServletResponse 的套件亦歸類在 javax.servlet.http

HttpServlet 實作了 GenericServlet 未實作的 service() 方法,將傳入的 ServletRequestServletResponse 轉換為 HttpServletRequestHttpServletResponse,並呼叫自己定義的、接受 HttpServletRequestHttpServletResponse 作為參數的 service() 方法,在這個 service() 方法中,根據 HTTP 請求方式,決定該呼叫 doGet()doPost() 等方法。你可以參考〈只有 doGet()、doPost()〉的內容。