這些Servlet知識你一定要知道,金九銀十大廠面試官都愛問
前言
Servlet是伺服器端的Java應用程式,可以生產動態Web頁面。透過JSP執行過程可以知道JSP最終被編譯成一個.class檔案,檢視該檔案對應的Java類,發現該Java類繼承自org.apache.jasper.runtime.HttpJspBase類,而HttpJspBase繼承自HttpServlet類,由此可知JSP第一次執行時實質上是被JSP引擎翻譯成了一個Servlet,然後再編譯,最後再執行。
自定義Servlet類繼 承HttpServlet抽象類,HttpServlet抽象類繼承自GenericServlet抽象類,GenericServlet抽象類實現了Servlet、ServletConfig和Serializable介面
Servlet宣告週期:
1、載入及例項化
Servlet容器負責載入和例項化Servlet。當客戶端第一次(在web.xml檔案中,通過load-on-startup標籤可以配置Servlet,當web專案釋出後立即建立Servlet例項) 給伺服器傳送該Servlet請求時,Servlet容器會載入並建立Servlet例項,(注意:預設情況下不是Tomcat伺服器或伺服器上的Web應用啟動的時候載入並例項化Servlet)。當客戶端(可以是非第一次請求的客戶端)再次向伺服器傳送該Servlet請求時,伺服器會從記憶體中查詢該Servlet例項,並用找到的Servlet例項處理使用者請求。
在該過程中,Servlet容器會建立一個ServletConfig物件,該物件包含了Servlet的初始化配置資訊。根據使用者請求的URL地址,Servlet容器會根據配置資訊查詢該請求對應的Servlet類,由容器建立並管理該Servlet。
2、初始化
在Servlet容器完成Servlet類的例項化操作後,Servlet容器會呼叫Servlet的init()方法(在javax.servelt.Servlet介面中定義)對該Servlet進行初始化。對於每一個Servlet例項來說,init()方法只會被呼叫一次。初始化的目的是讓Servlet在處理使用者請求之前,做一些必要的準備工作,例如建立資料庫連線,引用其他資源等。
3、處理請求
Servlet初始化之後,就處於就緒狀態等待接收使用者請求。當Servlet容器接收到客戶端針對該Servlet的請求後,首先會針對這個請求建立ServletRequest和ServletResponse物件,之後呼叫Servlet的service()方法並把這兩個引數傳遞給service()方法處理客戶端請求。Servlet例項通過ServletRequest物件獲得客戶端的請求,通過呼叫ServletResponse物件的方法進行響應。請求處理完畢,ServletRequest和ServletResponse物件被銷燬。
不管客戶端傳送請求的方式是Get還是POST,這個請求都由service方法來處理。在service方法的處理過程中,會根據客戶端傳送請求的方式不同,呼叫doGet和doPost方法分別進行處理,通過HttpServlet類中的service方法可以瞭解這一呼叫過程,如下程式碼:
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 { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < lastModified) { 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 { 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); } }
4、銷燬
銷燬Servlet 由Servlet容器完成。預設情況下,使用者第一次傳送Servlet請求,該Servlet載入、例項化、初始化、處理使用者請求,當請求處理完畢後,該Servlet通常情況下駐留在記憶體中,等待處理下一個針對該Servlet的請求。當下一個針對該Servlet的請求到達時,直接從記憶體中獲取該Servlet例項並對該請求進行處理。如果Tomcat這個Web應用伺服器關閉(伺服器上所有的Web應用都關閉),或者該Servlet所在的Web應用關閉,該Servlet例項會被銷燬。
Web應用被關閉時,Servlet容器會先呼叫Servlet例項的destroy方法,然後再銷燬Servlet例項,同時也會銷燬與Servlet相關聯的ServletConfig物件。程式設計師通常在destroy()方法的實現中釋放該Servlet所佔用的資源,如關閉資料庫連線,關閉檔案輸入/輸出流等。
通過Servlet宣告週期可以知道所建立的Servlet物件屬於單例。
Servlet2.X配置
在web.xml檔案中,通過在<web-app>節點下配置servlet元素和servlet-mapping元素,把使用者訪問的URL對映到指定的Servlet類,如下程式碼:
<web-app> <!-- 省略其他配置 --> <servlet> <!-- servlet-name指定Servlet名,要與下面servlet-mapping元素中的servlet-name保持一致 --> <servlet-name>doLogin</servlet-name> <!-- servlet-class對應著Servlet類完全限定名 --> <servlet-class>com.jd.serlvet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <!-- servlet-name要與上面servlet元素中的servlet-name保持一致 --> <servlet-name>doLogin</servlet-name> <!-- url-pattern設定當前Servlet在瀏覽器中執行時的url --> <url-pattern>/doLogin</url-pattern> </servlet-mapping> </web-app>
上面採用了精確匹配的形式配置了URL到Servlet之間的對映關係,接下來介紹兩種非精確匹配的Servlet配置方式:
<!-- 對doLogin路徑下的所有請求都由doLogin對應的Servlet類進行處理 --> <servlet-mapping> <servlet-name>doLogin</servlet-name> <url-pattern>/doLogin/*</url-pattern> </servlet-mapping> <!-- 對所有以.do為字尾的請求都由doLogin對應的Servlet類進行處理 --> <servlet-mapping> <servlet-name>doLogin</servlet-name> <!-- 不能為/*.do --> <url-pattern>*.do</url-pattern> </servlet-mapping>
在配置了URL與Servlet的對映後,當Servlet容器收到一個請求時,首先確定是由哪個Web應用響應這個請求,然後從該Web應用的web.xml檔案中查詢URL對應的Servlet類進行處理。
Servlet初始化引數設定
在web.xml檔案中配置Servlet時,還可以在servlet元素中新增init-param元素預先對Servlet進行初始化設定,當Servlet載入時即可從該Servlet配置檔案中獲取初始化引數。
<!-- 省略其他配置 --> <servlet> <servlet-name>doLogin</servlet-name> <servlet-class>com.jd.serlvet.LoginServlet</servlet-class> <!-- 配置多個初始化引數,則需要寫多個init-param元素 --> <init-param> <param-name>name</param-name> <param-value>Tom</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>doLogin</servlet-name> <url-pattern>/doLogin</url-pattern> </servlet-mapping>
如何獲取:
a、在無參init方法中直接呼叫getInitParameter(String name)方法即可,如下程式碼:
@Override public void init() throws ServletException { String name = getInitParameter("name"); System.out.println(name); }
b、在引數為ServletConfig的方法中呼叫ServletConfig內getInitParameter(String name)方法即可,如下程式碼:
@Override public void init(ServletConfig config) throws ServletException { String name = config.getInitParameter("name"); System.out.println(name); }
Servlet上下文(環境物件)初始化引數設定
有時候不僅需要針對單個Servlet進行初始化引數設定,還需要對包含該Web引用中所有Servlet的環境物件進行初始化引數設定,使該引數能被所有的Servlet共享,如下程式碼:
<!-- 省略其他配置 --> <!-- 配置多個初始化引數,則需要寫多個context-param元素 --> <context-param> <param-name>name</param-name> <param-value>Tom</param-value> </context-param> <servlet> <servlet-name>doLogin</servlet-name> <servlet-class>com.jd.serlvet.LoginServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>doLogin</servlet-name> <url-pattern>/doLogin</url-pattern> </servlet-mapping> </web-app>
如何獲取:
a、在無參init方法中直接呼叫getServletContext ()方法獲取Servlet上下文物件,然後使用該物件呼叫getInitParameter方法即可,如下程式碼:
@Override public void init() throws ServletException { String name = getServletContext ().getInitParameter("name"); System.out.println(name); }
b、在引數為ServletConfig的方法中呼叫ServletConfig內getServletContext ()方法獲取Servlet上下文物件,然後使用該物件呼叫getInitParameter方法即可,如下程式碼:
@Override public void init(ServletConfig config) throws ServletException { ServletContext servletContext = config.getServletContext(); String name = servletContext.getInitParameter("name"); System.out.println(name); }
Servlet 3.0
Servlet API包含javax.servlet和javax.servlet.http兩個包,從Servlet 3.0開始,為了實現Servlet3.0的一些新特性,又增加了javax.sevlet.annotation和javax.sevlet.descriptor兩個包,Tomcat伺服器必須是7.0及其以上版本
Servlet3.0的重大革新之一是支援註解,通過使用註解定義並部署Servlet,程式設計師無須在web.xml檔案中配置Servlet,如下程式碼:
@WebServlet(name="doLogin",urlPatterns="/doLogin",initParams={@WebInitParam(name="name",value="Tom")}) public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.sendRedirect("success.jsp"); } }
說明:
name屬性:指定Servlet名,類似於web.xml中servlet-name元素;
urlPatterns屬性:指定訪問URL,類似於web.xml中的url-pattern元素;可以是陣列,URL之間使用逗號間隔。
initParams屬性:設定初始化引數,該屬性中使用@WebInitParam註解設定單個初始化引數;在@WebInitParam註解中,name屬性指定引數名,類似於web.xml中的param-name元素;value屬性指定引數值,類似於web.xml中的param-value元素。可以在initParams屬性中配置多個@WebInitParam註解,用於初始化多個引數。
wb.xml:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>name</param-name> <param-value>lucy</param-value> </context-param> <servlet> <servlet-name>TestServlet</servlet-name> <display-name>TestServlet</display-name> <description></description> <servlet-class>com.jd.servlet.TestServlet</servlet-class> <init-param> <param-name>mobile</param-name> <param-value>120</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/TestServlet</url-pattern> </servlet-mapping> </web-app>
TestServlet.java:
package com.jd.servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class TestServlet */ public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; //Servlet物件屬於單例項(程式執行結束之前,快取中只有一個物件存在) public TestServlet() { //用於為成員變數賦值,會觸發物件建立:預設情況下第一次使用該Servlet時建立物件執行; //web.xml中加入<load-on-startup>1</load-on-startup>,在tomcat啟動時物件建立,TestServlet執行,隨之init()方法也立即執行 super(); System.out.println("TestServlet"+this); } // @Override public void destroy() { super.destroy(); System.out.println("destroy"+this); } @Override public void init() throws ServletException {//初始化;對於每一個Servlet例項來說,建立物件執行init()方法,並且只會被呼叫一次 super.init(); String name=getServletContext().getInitParameter("name");//呼叫公共引數 System.out.println("1111111"+name); System.out.println("init())"+this); } @Override public void init(ServletConfig config) throws ServletException { super.init(config); String name=config.getServletContext().getInitParameter("name");//呼叫公共引數 System.out.println("你好"+name); String mobile=config.getInitParameter("mobile");//呼叫私人蔘數 System.out.println("快打"+mobile); System.out.println("init(config))"+this); } //請求最先到達service判斷執行哪個方法,doGet還是doPost @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.service(req, resp); System.out.println("service"+this); } //a標籤,form表單method是 get方法 非同步預設type是get方法 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("doGet"+this); } //form表單method是 post方法 非同步指定type是post方法 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("doPost"+this); } }
最後
感謝你看到這裡,看完有什麼的不懂的可以在評論區問我,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!