Servlet底层原理、Servlet实现方式、Servlet生命周期
Servlet簡介
Servlet定義
Servlet是一個Java應用程序,運行在服務器端,用來處理客戶端請求并作出響應的程序。
Servlet的特點
(1)Servlet對像,由Servlet容器(Tomcat)創建。
(2)Servlet是一個接口:位于javax.servlet包中。
(3)service方法用于接收用戶的請求并返回響應。
(4)用戶訪問時多次被執行(可以統計網站的訪問量)。
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實際上是一個接口,其中包含init、getServletConfig、service、getServletInfo、destroy幾個接口方法。
實現Servlet接口
package cn.chenhao;import java.io.IOException;import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;public class FirstServlet implements Servlet {/**init方法*/@Overridepublic void init(ServletConfig paramServletConfig) throws ServletException {}/**getServletConfig方法*/@Overridepublic ServletConfig getServletConfig() {return null;}/**service方法*/@Overridepublic void service(ServletRequest paramServletRequest,ServletResponse paramServletResponse) throws ServletException,IOException {}/**getServletInfo方法*/@Overridepublic String getServletInfo() {return null;}/**destroy方法*/@Overridepublic void destroy() {} }我們需要實現servlet接口里面所有的方法,這對于我們開發來說是很繁瑣的。
Servlet 生命周期的方法: 以下方法都是由 Serlvet 容器負責調用.
1). 構造器: 只被調用一次. 只有第一次請求 Servlet 時, 創建 Servlet 的實例. 調用構造器. 這說明 Serlvet 的單實例的!
2). init 方法: 只被調用一次. 在創建好實例后立即被調用. 用于初始化當前 Servlet.
3). service: 被多次調用. 每次請求都會調用 service 方法. 實際用于響應請求的.
4). destroy: 只被調用一次. 在當前 Servlet 所在的 WEB 應用被卸載前調用. 用于釋放當前 Servlet 所占用的資源.
下面兩個方法是開發者調用
1). getServletConfig: 返回一個ServletConfig對象,其中包含這個servlet初始化和啟動參數.
2). getServletinfo: 返回有關servlet的信息,如作者、版本和版權.
在 web.xml 文件中配置和映射這個 Servlet
<!-- 配置和映射 Servlet --> <servlet><!-- Servlet 注冊的名字 --><servlet-name>helloServlet</servlet-name><!-- Servlet 的全類名 --><servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class> </servlet><servlet-mapping><!-- 需要和某一個 servlet 節點的 serlvet-name 子節點的文本節點一致 --><servlet-name>helloServlet</servlet-name><!-- 映射具體的訪問路徑: / 代表當前 WEB 應用的根目錄. --><url-pattern>/hello</url-pattern> </servlet-mapping>?
load-on-startup 參數
1). 配置在 servlet 節點中:
<servlet><!-- Servlet 注冊的名字 --><servlet-name>secondServlet</servlet-name><!-- Servlet 的全類名 --><servlet-class>com.atguigu.javaweb.SecondServlet</servlet-class><!-- 可以指定 Servlet 被創建的時機 --><load-on-startup>2</load-on-startup> </servlet>2). load-on-startup: 可以指定 Serlvet 被創建的時機. 若為負數, 則在第一次請求時被創建.若為 0 或正數, 則在當前 WEB 應用被Serlvet 容器加載時創建實例, 且數組越小越早被創建.
關于 serlvet-mapping
1). 同一個Servlet可以被映射到多個URL上,即多個 <servlet-mapping> 元素的<servlet-name>子元素的設置值可以是同一個
Servlet的注冊名。
2). 在Servlet映射到的URL中也可以使用 * 通配符,但是只能有兩種固定的格式:
一種格式是“*.擴展名”,另一種格式是以正斜杠(/)開頭并以“/*”結尾。
注意: 以下的既帶 / 又帶擴展名的不合法.?
<servlet-mapping><servlet-name>secondServlet</servlet-name><url-pattern>/*.action</url-pattern> </servlet-mapping>Servlet生命周期
實例化:在第一次訪問或啟動tomcat時,tomcat會調用此無參構造方法實例化servlet。
初始化:tomcat在實例化此servlet后,會立即調用init方法初始化servlet。
就緒:容器收到請求后調用servlet的service方法來處理請求。
銷毀:容器依據自身算法刪除servlet對象,刪除前會調用destory方法
其中實例化,初始化,銷毀只會執行一次,service方法執行多次,默認情況下servlet是在第一次接受到用戶請求的情況下才會實例化,可以在web.xml中的<servlet><servlet>標簽內添加一個<load-on-startup>1<load-on-startup>配置,此時在啟動tomcat時會創建servlet實例。
ServletConfig
封裝了 Serlvet 的配置信息, 并且可以獲取 ServletContext 對象
1). 配置 Serlvet 的初始化參數
<servlet><servlet-name>helloServlet</servlet-name><servlet-class>com.atguigu.javaweb.HelloServlet</servlet-class><!-- 配置 Serlvet 的初始化參數。 且節點必須在 load-on-startup 節點的前面 --><init-param><!-- 參數名 --><param-name>user</param-name><!-- 參數值 --><param-value>root</param-value></init-param><init-param><param-name>password</param-name><param-value>1230</param-value></init-param><load-on-startup>-1</load-on-startup></servlet>2). 獲取初始化參數:?
getInitParameter(String name): 獲取指定參數名的初始化參數 getInitParameterNames(): 獲取參數名組成的 Enumeration 對象. String user = servletConfig.getInitParameter("user"); System.out.println("user: " + user);Enumeration<String> names = servletConfig.getInitParameterNames(); while(names.hasMoreElements()){String name = names.nextElement();String value = servletConfig.getInitParameter(name);System.out.println("^^" + name + ": " + value); }ServletContext
1). 可以由 SerlvetConfig 獲取:
ServletContext servletContext = servletConfig.getServletContext();2). 該對象代表當前 WEB 應用: 可以認為 SerlvetContext 是當前 WEB 應用的一個大管家. 可以從中獲取到當前 WEB 應用的各個方面的信息.
①. 獲取當前 WEB 應用的初始化參數
設置初始化參數: 可以為所有的 Servlet 所獲取, 而 Servlet 的初始化參數只用那個 Serlvet 可以獲取.
<!-- 配置當前 WEB 應用的初始化參數 --><context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
代碼:
ServletContext servletContext = servletConfig.getServletContext();String driver = servletContext.getInitParameter("driver");
System.out.println("driver:" + driver);
Enumeration<String> names2 = servletContext.getInitParameterNames();
while(names2.hasMoreElements()){
String name = names2.nextElement();
System.out.println("-->" + name);?
}
②. 獲取當前 WEB 應用的某一個文件在服務器上的絕對路徑, 而不是部署前的路徑
String realPath = servletContext.getRealPath("/note.txt");③. 獲取當前 WEB 應用的名稱:?
String contextPath = servletContext.getContextPath();④. 獲取當前 WEB 應用的某一個文件對應的輸入流.?
InputStream is2 = servletContext.getResourceAsStream("/WEB-INF/classes/jdbc.properties");如何在 Serlvet 中獲取請求信息
1). Servlet 的 service() 方法用于應答請求: 因為每次請求都會調用 service() 方法
public void service(ServletRequest request, ServletResponse response)throws ServletException, IOExceptionServletRequest: 封裝了請求信息. 可以從中獲取到任何的請求信息.
ServletResponse: 封裝了響應信息, 如果想給用戶什么響應, 具體可以使用該接口的方法實現.
這兩個接口的實現類都是服務器給予實現的, 并在服務器調用 service 方法時傳入.
2). ServletRequest: 封裝了請求信息. 可以從中獲取到任何的請求信息.
①. 獲取請求參數:
> String getParameter(String name): 根據請求參數的名字, 返回參數值. 若請求參數有多個值(例如 checkbox), 該方法只能獲取到第一個提交的值.> String[] getParameterValues(String name): 根據請求參數的名字, 返回請求參數對應的字符串數組.> Enumeration getParameterNames(): 返回參數名對應的 Enumeration 對象, 類似于 ServletConfig(或 ServletContext) 的 getInitParameterNames() 方法.> Map getParameterMap(): 返回請求參數的鍵值對: key: 參數名, value: 參數值, String 數組類型.②. 獲取請求的 URI:
HttpServletRequest httpServletRequest = (HttpServletRequest) request;String requestURI = httpServletRequest.getRequestURI(); System.out.println(requestURI); // /day_29/loginServlet③. 獲取請求方式:?
String method = httpServletRequest.getMethod(); System.out.println(method); //GET④. 若是一個 GET 請求, 獲取請求參數對應的那個字符串, 即 ? 后的那個字符串.?
String queryString = httpServletRequest.getQueryString(); System.out.println(queryString); //user=atguigu&password=123456&interesting=game&interesting=party&interesting=shopping⑤. 獲取請求的 Serlvet 的映射路徑?
String servletPath = httpServletRequest.getServletPath(); System.out.println(servletPath); // /loginServlet?
3). HttpServletRequest: 是 SerlvetRequest 的子接口. 針對于 HTTP 請求所定義. 里邊包含了大量獲取 HTTP 請求相關的方法.?
4). ServletResponse: 封裝了響應信息, 如果想給用戶什么響應, 具體可以使用該接口的方法實現.?
①. *getWriter(): 返回 PrintWriter 對象. 調用該對象的 print() 方法, 將把 print() 中的參數直接打印到客戶的瀏覽器上.?
②. 設置響應的內容類型: response.setContentType("application/msword");
③. void sendRedirect(String location): 請求的重定向. (此方法為 HttpServletResponse 中定義.)
?
GenericServlet
1). 是一個 Serlvet. 是 Servlet 接口和 ServletConfig 接口的實現類. 但是一個抽象類. 其中的 service 方法為抽象方法
2). 如果新建的 Servlet 程序直接繼承 GenericSerlvet 會使開發更簡潔.
3). 具體實現:
①. 在 GenericServlet 中聲明了一個 SerlvetConfig 類型的成員變量, 在 init(ServletConfig) 方法中對其進行了初始化
②. 利用 servletConfig 成員變量的方法實現了 ServletConfig 接口的方法
③. 還定義了一個 init() 方法, 在 init(SerlvetConfig) 方法中對其進行調用, 子類可以直接覆蓋 init() 在其中實現對 Servlet 的初始化.
④.?不建議直接覆蓋 init(ServletConfig), 因為如果忘記編寫 super.init(config); 而還是用了 SerlvetConfig 接口的方法,則會出現空指針異常.
⑤. 新建的 init(){} 并非 Serlvet 的生命周期方法. 而 init(ServletConfig) 是生命周期相關的方法.
HttpServlet
1). 是一個 Servlet, 繼承自 GenericServlet. 針對于 HTTP 協議所定制.
2). 在 service() 方法中直接把 ServletReuqest 和 ServletResponse 轉為 HttpServletRequest 和 HttpServletResponse.并調用了重載的 service(HttpServletRequest, HttpServletResponse)
? ? 在 service(HttpServletRequest, HttpServletResponse) 獲取了請求方式: request.getMethod(). 根據請求方式有創建了doXxx() 方法(xxx 為具體的請求方式, 比如 doGet, doPost)
@Overridepublic 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); }public void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//1. 獲取請求方式.String method = request.getMethod();//2. 根據請求方式再調用對應的處理方法if("GET".equalsIgnoreCase(method)){doGet(request, response);}else if("POST".equalsIgnoreCase(method)){doPost(request, response);} }public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{// TODO Auto-generated method stub }public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Auto-generated method stub }3). 實際開發中, 直接繼承 HttpServlet, 并根據請求方式復寫 doXxx() 方法即可.
4). 好處: 直接由針對性的覆蓋 doXxx() 方法; 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要強轉.
推薦博客
程序員寫代碼之外,如何再賺一份工資?
Servlet的生命周期
Servlet生命周期圖
Servlet生命周期簡述
(1)加載和實例化
當Servlet容器啟動或客戶端發送一個請求時,Servlet容器會查找內存中是否存在該Servlet實例,若存在,則直接讀取該實例響應請求;如果不存在,就創建一個Servlet實例。
(2) 初始化
實例化后,Servlet容器將調用Servlet的init()方法進行初始化(一些準備工作或資源預加載工作)。
(3)服務
初始化后,Servlet處于能響應請求的就緒狀態。當接收到客戶端請求時,調用service()的方法處理客戶端請求,HttpServlet的service()方法會根據不同的請求 轉調不同的doXxx()方法,比如 doGet, doPost。
(4)銷毀
當Servlet容器關閉時,Servlet實例也隨時銷毀。其間,Servlet容器會調用Servlet 的destroy()方法去判斷該Servlet是否應當被釋放(或回收資源)。
?
其中實例化,初始化,銷毀只會執行一次,service方法執行多次,默認情況下servlet是在第一次接受到用戶請求的情況下才會實例化,可以在web.xml中的<servlet><servlet>標簽內添加一個<load-on-startup>1<load-on-startup>配置,此時在啟動tomcat時會創建servlet實例。
?
轉載于:https://www.cnblogs.com/java-chen-hao/p/10688617.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Servlet底层原理、Servlet实现方式、Servlet生命周期的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 首个AI国际标准有望明年出台,创新工场等
- 下一篇: 实现日志管理的两种方式:aop、拦截器