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