詳細理解servlet實現的幾種方式和生命周期


現在很多的開發都是用的框架,然后很多同學學習的時候又是直接接觸的框架,對於底層的一些開發,完全沒有任何的了解。雖然對於業務上面來說,沒有什么問題。但是很多時候當你被面試問到,或者是想要了解框架底層原理的時候,這就不得不知道了。所以今天詳細說說它。

 

開發servlet的三種方式

1、實現servlet接口(偏向底層)

2、繼承GenericServlet(覺得1不好用,就開發了這個,現在基本沒啥用)

3、繼承HttpServlet(現在大多數用這個)

 

理解實現servlet接口的方式,理解servlet生命周期

首先當servlet第一次被調用的時候,會調用servlet的init方法,把servlet實例裝載到內存中。

之后會調用service方法,當第二次servlet被訪問的時候就會直接調用service函數。

只有當web應用關閉,或者容器關閉,或者電腦關閉時候,才會調用destroy方法銷毀servlet

 

下面是瀏覽器發出請求后servlet執行的流程圖

 

Servlet接口有五個方法

init初始化,就是把servlet裝載到內存中,只會被調用一次

getServletConfig獲取servletConfig對象

service主要的服務方法,放業務邏輯,每次都會被調用

getServletInfo得到servlet配置信息

destroy銷毀該servlet,從內存中清除掉

 

繼承GenericServlet

GenericServlet實現了servlet接口

然后只有一個抽象方法需要你自己去重寫

那就是service方法,所以相比來說init別的方法他都幫你實現好了,只要你寫service方法就可以了。

至少看起來繼承GenericServlet比直接實現servlet接口要方便

這個類是在javax.servlet.GenericServlet下的

 

 

繼承HttpServlet

因為后來發現servlet主要是為了服務於http請求的,而且發現GenericServlet對於http來說還不夠好

所以有了HttpServlet,首先它是繼承自GenericServlet

然后它有很多http相關的方法,post,get,put等待

用戶可以根據自己需要來實現這些方法

每個過來的請求都會調用service方法,最后service會根據不用的請求分發到不同的地方去做。

下面的問題中會在源碼中詳細說明。

 

 

下面有關servlet service描述錯誤的是?

1、不管是post還是get方法提交過來的連接,都會在service中處理

每次請求都會調用service方法,最終都會在service中處理,正確;


2、doGet/doPost 則是在 javax.servlet.GenericServlet 中實現的

GenericServlet只是繼承了Servlet的接口,實現了它其中的5個方法,其中需要用戶重寫的是service方法,而doGet/doPost是因為之后出現了HttpServlet才有的,是針對http請求才有了這個類,才有了doPost和doGet,所以是錯誤的。


3、service()是在javax.servlet.Servlet接口中定義的

Servlet接口一共定義了5個方法,其中就有service(),正確;


4、service判斷請求類型,決定是調用doGet還是doPost方法

 

下面詳細說說最后一個選項。

我們來看一看源碼

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) {
        // servlet doesn't support if-modified-since, no reason
        // to go through further expensive logic
        doGet(req, resp);
        } else {
        long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
        if (ifModifiedSince < (lastModified / 1000 * 1000)) {
            // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
            maybeSetLastModified(resp, lastModified);
            doGet(req, resp);
        } else {
            resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
        
    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);    
        
    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);
        
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);
        
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);
        
    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);
        
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
    }

這個就是HttpServlet中service方法的源碼

首先我們看到的就是String method = req.getMethod();

這個就是通過request獲取方法

然后根據方法判斷調用哪一個方法

要說明的是前面它已經定義好了那些字符串

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";
所以第四個選項說:service判斷請求類型,決定是調用doGet還是doPost方法,是正確的。

需要指出的是

前面說過

HttpServlet是繼承自GenericServlet,而GenericServlet需要用戶實現一個service,剛才我們看到的是它自己的

而在HttpServlet中其實是有的。它肯定要寫這樣一個方法的。

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

源碼是這樣的,它會把原來的ServletRequest 請求直接強轉換成HttpServletRequest然后再去調用它正真的service方法。

這點是需要指出的,HttpServletRequest比ServletRequest進行了進一步的封裝,方法更適合http。

 

Servlet的生命周期分為5個階段:加載、創建、初始化、處理客戶請求、卸載。
(1)加載:容器通過類加載器使用servlet類對應的文件加載servlet
(2)創建:通過調用servlet構造函數創建一個servlet對象
(3)初始化:調用init方法初始化
(4)處理客戶請求:每當有一個客戶請求,容器會創建一個線程來處理客戶請求
(5)卸載:調用destroy方法讓servlet自己釋放其占用的資源


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM