1. 程式人生 > >Servlet 2.x 規範

Servlet 2.x 規範

Servlet 2.x 規範

sun 公司制訂的一種用來擴充套件 web 伺服器功能的元件規範。

Servlet 2.x 元件關係

  1. Servlet 介面:init(ServletConfig config)、service(ServletRequest req, ServletResponse res)、destroy()
  2. GenericServlet 抽象類:實現了 Servlet 介面中的 init, destroy 方法
  3. HttpServlet 抽象類:繼承了 GenericServlet 抽象類,實現了 service()
  4. ServletConfig 介面:String getInitParameter(String paraName)
  5. ServletRequest 介面:HttpServletRequest 的父介面
  6. ServletResponse 介面:HttpServletResponse 的父介面

一、Servlet

1.1 Servlet 的生命週期

Servlet 的生命週期指 Servlet 容器如何去建立 Servlet 物件、如何給 Servlet 物件分配資源、如何呼叫 Servlet 物件的方法來處理請求、以及如何銷燬 Servlet 物件的整個過程。

Servlet 生命週期的四個階段:

(1) 例項化:容器呼叫 Servlet 的構造器,建立 Servlet 物件。

情況1:容器收到請求後才建立 Servlet 物件。預設,容器只會為 Servlet 建立唯一一個例項。

情況2: 容器啟動時交某些 Servlet 物件建立好(需要配置 load-on-startup)。load-on-startup 引數值必須是 >=0 的整數,越小優先順序(即先例項化)越高。

(2) 初始化:容器在建立好 Servlet 物件後,立即呼叫 init() 方法。

init() 只執行一次

GenericServlet 已經實現了 init(),該方法會將容器建立好的 ServletConfig 物件作為引數傳給 init()。

ServletConfig 物件提供一個 getInitParameter() 來訪問 Servlet 的初始化引數。

如果 GenericServlet 的 init() 提供的初始化操作不滿足需要,可以重寫 init() 無參方法,不重寫 init(ServletConfig config)

(3) 就緒

Servlet 物件可以呼叫了,容器收到請求後,會呼叫 Servlet 物件的 service() ,該方法會依據請求型別(get/post)分別呼叫 doGet(), doPost()

(4) 銷燬:Servlet 容器在銷燬 Servlet 物件之前,會呼叫 destroy() 方法。

1.2 Servlet 如何處理請求資源路徑

  1. Servlet 容器會先假設訪問的是一個 Servlet ,會依據應用名(appname)找到應用所在的資料夾,然後找到 web.xml 檔案。

  2. 匹配

    • 精確匹配(完全匹配)
    • 萬用字元匹配:使用 * 匹配任意長度的字串。eg:
    • 字尾匹配:使用 . 開頭,後面可以接任意字元。eg: .do
  3. 如果都不匹配,則容器認為訪問的是一個靜態資原始檔(html/css/js),如果找到則返回,否則返回404。

1.3 Servlet 是如何執行的?

  1. 瀏覽器依據 ip, port 建立與 Servlet 容器之間的連線。
  2. 瀏覽器將請求資料打包(即按照 http 協議的要求,將相關資料封閉成一個數據包,即請求資料包)併發送給 Servlet 容器。
  3. Servlet 容器解析請求資料包,並將解析後的資料放到 request 物件上。同時建立一個 response 物件。
  4. Servlet 容器依據請求資源路徑找到 Servlet 的配置,然後建立 Servlet 物件。
  5. Servlet 呼叫 service 方法,並且會將事先建立好的 request 物件和 response 物件作為 service 方法的引數傳遞給 Servlet 物件。
  6. Servlet 通過 request 物件獲得請求引數,進行相應的處理,然後將處理結果寫到 response 物件上。
  7. Servlet 讀取 response 物件上的資料,然後將處理結果打包(響應資料包)併發送給瀏覽器。
  8. 瀏覽器解析響應資料包,將返回的資料展現給使用者。

1.4 例項

public class HelloWorldServlet extends HttpServlet {
    public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
        //1、讀請求引數值
        String qtyStr = req.getParameter("qty");
        int qty = Integer.parseInt(qtyStr);
        //2、處理請求
        String rs = "";
        for (int i = 0; i < qty; i++) {
            rs += "<h1>Hello World</h1>";
        }
        //3、設定一個訊息頭content-type,告訴瀏覽器返回的資料型別是一個html文件及編碼格式
        //告訴伺服器使用out輸出時使用指定的編碼格式進行編碼
        res.setContentType("text/html;charset=utf-8");
        //4、獲得一個輸出流
        PrintWriter out = res.getWriter();
        //5、呼叫流的方法進行輸出,其實質是將處理結果寫到了res物件上
        out.println(rs);
        out.close();
    }
}

配置 WEB-INF/web.xml 配製檔案

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>helloWord</servlet-name>
        <!--類名要完整(包名,類名都要全)-->
        <servlet-class>com.herolei.HelloWorldServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>helloWord</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

啟動程式,訪問 http://localhost:8080/hello?qty=30

補充:web 打包後的目錄如下

appname(應用名)
  └──WEB-INF
      ├──classes    .class檔案
      ├──lib        .jar檔案,lib資料夾可選
      └──web.xml    部署描述檔案

二、Listener

Servlet 規範當中定義的一種特殊的元件,用來監聽容器產生的事件並進行處理。

容器會產生兩大類事件:

  1. 生命週期相關的事件:容器在建立或者銷燬 request, servletContext(Servlet 上下文)時產生的事件。對應的介面有 ServletRequestListener、ServletContextListener。
  2. 繫結相關的事件:容器呼叫了 request, servletContext 的 setAttribute, removeAttribute 時產生的事件。。對應的介面有 ServletContextAttributeListener、ServletRequestAttributeListener。
public interface ServletContextListener extends EventListener {
    // 容器初始化
    void contextInitialized(ServletContextEvent ctx);
    // 容器銷燬
    void contextDestroyed(ServletContextEvent ctx);
}

public interface ServletContextAttributeListener extends EventListener {
    void attributeAdded(ServletContextAttributeEvent event);
    void attributeRemoved(ServletContextAttributeEvent event);
    void attributeReplaced(ServletContextAttributeEvent event);
}

三、Filter

public interface Filter {
    // 初始化 Filter
    void init(FilterConfig filterConfig) throws ServletException;

    // 呼叫,如果要繼續呼叫下一個 Filter,需要呼叫 chain.doFilter(request, response)
    void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    // 銷燬
    public void destroy();
}

public interface FilterChain {
    void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}

參考:

  1. 《Servlet 規範》:https://www.runoob.com/servlet/servlet-life-cycle.html

每天用心記錄一點點。內容也許不重要,但習慣很重要!