1. 程式人生 > >Java基礎面試題(11)----Servlet的理解和生命週期

Java基礎面試題(11)----Servlet的理解和生命週期

問題

說說對servlet的理解? 什麼是servlet的生命週期?

回答

Servlet是什麼?

selvet(server applet),全稱Java Servlet,使用Java語言編寫的服務端程式,這些servlet都需要繼承HttpServlet這個抽象類,重寫的doGet()和doPost()這兩個方法,或者主動重寫service()方法。HttpServlet最終實現的是Servlet這個介面。 其主要的功能是在於互動的瀏覽和修改資料,生成動態的web內容,servlet運行於支援Java的應用伺服器中。

servlet是可以單例多執行緒,多個使用者在頁面進行請求的時候,實際只有一個Servlet物件,因為這些操作都是統一的,沒有必要生產多個物件造成資源浪費。具體可以瞭解一下單例模式的相關知識。

Serlvet的生命週期

首先看一下我們自定義的MySerlvet的繼承關係圖 在這裡插入圖片描述 再看一下Servlet介面中定義的方法,這裡實際是定義了servlet的宣告週期

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();
}

執行的過程大致如下:

  • servlet啟動時,開始載入servet,生命週期開始,看一下原始碼,兩個被繼承的類在被繼承的時候,都會載入相關的靜態資源,所以自定義的類一旦被建立,就會在編譯器自動載入靜態資源。
public abstract class HttpServlet extends GenericServlet implements Serializable {
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    //靜態資源在編譯器就會被載入
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");


  // GenericServlet類
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
    private transient ServletConfig config;
  • servlet被伺服器例項化後,容器執行init()方法,我們可以對init()方法進行自己的實現。 **在一個Servlet的生命週期中,init方法只會被執行一次,**之後無論使用者執行多少次請求,都不會在呼叫該方法。 關於init方法的執行時機,有兩種方式可選,一般的是在伺服器啟動後第一個使用者請求改Servlet是呼叫,你也可以設定該Servlet在伺服器啟動後自動執行。 init方法負責簡單的建立或者載入一些資料,這些資料將用於該Servlet的整個生命週期中。
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
...................
初始化方法
public void init() throws ServletException {
    }
....................
}
  • 請求到達時執行其service()方法,service方法自動派遣執行對應的doGet()或者doPost()方法, 每一次請求伺服器都會開啟一個新的執行緒並執行一次service方法。
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
...................

//在這裡定義抽象的service()方法
 public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
 
....................

//httpServlet類
public abstract class HttpServlet extends GenericServlet implements Serializable {

................
//service方法做了一系列的方法判斷,按照子類的相關資訊給出對應的類
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
...................

}

  • 當伺服器伺服器決定將其例項銷燬的時候,會呼叫destroy()方法,這個方法和init()方法的實現位置和型別一樣,父類中定義了空方法,可以自己重寫。該方法在整個生命週期中,也是隻會被呼叫一次,在Servlet物件被銷燬是呼叫,在servlet中,我們可以做一些資源的釋放等操作,執行destory()方法之後的servlet物件,會等待jvm虛擬機器的垃圾回收機制擇時回收。
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
...................
銷燬的方法
public void destroy() throws ServletException {
    }
....................
}