誰再問Servlet的問題,我就親自上門來教學了

鍋外的大佬發表於2020-12-18

1. 概述

在這篇簡短的文章中,我們將從概念上理解什麼是servletservlet 容器以及它們是如何工作的
同時,還能在請求、響應、會話物件、共享變數和多執行緒的上下文中看到它們的身影。

2. Servlets 和 它的容器

servletJEE 用於 web 開發常用的元件。它們基本上是執行在容器邊界內的Java程式。總的來說,它們負責接受請求,處理請求,並返回響應

要使用它們,首先需要容器註冊 servlet ,無論是基於 JEE 還是基於 Spring 的容器,都可以在啟動時接收它們。在開始時,容器通過呼叫 init() 方法來例項化 servlet
初始化完成後,servlet 就可以接受傳入的請求。隨後,容器將這些請求定向到 servletservice 方法中進行處理。之後,它根據HTTP請求型別將請求進一步委託給適當的方法,例如 doGet()doPost()

使用 destroy(),容器會銷燬 servlet,並且不再接受傳入的請求。我們將這個 init-service-destroy 的迴圈稱為 servlet 的生命週期。

現在我們從容器的角度來看,比如 Apache TomcatJetty 在啟動時,建立一個 ServletContext 的物件,ServletContext 的任務是充當伺服器或容器的記憶體,並記住與web應用程式相關聯的所有servlet、過濾器和偵聽器,如其 web.xml檔案或等效註解。在容器停止之前,ServletContext 會一直保留它。

不管怎麼說,servletload-on-startup 引數扮演重要的角色 。如果此引數的值大於零,則只有在啟動時伺服器才會對其進行初始化。如果未指定此引數,則在請求第一次命中 servlet時呼叫它的 init()
file

3. Request, Response 和 Session

在上一節中,我們討論了傳送請求和接收響應,這基本上是任何CS應用程式的基礎。現在,我們從servlet的角度來詳細瞭解它們。

在這種情況下,請求將由 HttpServletRequest 表示,響應將用 HttpServletResponse 表示。

每當瀏覽器或curl命令等傳送請求時,容器都會建立一個新的 HttpServletRequestHttpServletResponse 物件。然後將這些新物件傳遞給 servletservice方法。基於 HttpServletRequestmethod 屬性,此方法確定應呼叫哪個 doXXX方法。

除了有關方法的資訊外,request物件還攜帶其他資訊,如頭、引數和主體。類似地,HttpServletResponse物件也攜帶頭、引數和主體——我們可以在 servletdoXXX 方法中設定它們。

這些物件的生命稍縱即逝。當客戶端獲得響應時,伺服器將標記用於垃圾回收的請求和響應物件。
那麼我們如何在隨後的客戶端請求或連線之間保持一個狀態?答案就是 HttpSession

原理是將這些物件繫結到使用者會話,以便與特定使用者相關的資訊可以跨多個請求持久化。這通常是通過使用cookies的概念,使用 [JSESSIONID] 作為給定會話的唯一識別符號。我們可以在web.xml中指定會話的超時時長。

<session-config>
    <session-timeout>10</session-timeout>
</session-config>

以上配置表示,如果會話空閒了10分鐘,伺服器將丟棄它。任何後續請求都將建立一個新的會話。

4. Servlets 共享資料

根據所需的範圍,servlet 可以通過多種方式共享資料。

正如在前面的章節中提到的,不同的物件有不同的生命週期。HttpServletRequestHttpServletResponse 物件只存在於一個 servlet 呼叫之間。HttpSession只要它處於活動狀態並且沒有超時,它就會一直存在。

ServletContext的生命週期最長。它與Web應用程式一起誕生,只有當應用程式本身關閉時才會被銷燬。由於servlet、filter 和 listener 例項與上下文繫結,所以只要web應用程式啟動並執行,它們也會一直存在。

因此,如果我們的需求是在所有servlet之間共享資料,假設我們要計算站點的訪問者數量,那麼我們應該將變數放在 ServletContext 中。如果我們需要在一個會話中共享資料,那麼我們就把它儲存在會話範圍內。在本例中,使用者名稱就是一個例子。

最後,還有與單個請求的資料相關的請求範圍,比如請求有效負載。

5. 處理多執行緒

多個HttpServletRequest 物件彼此共享 servlet,這樣每個請求都使用它自己的 servlet 例項執行緒進行操作。

就執行緒安全而言,這實際上表明:我們不應該將請求或會話範圍內的資料指定為 servlet的例項變數。

例如,下面的程式碼片段:

public class ExampleThree extends HttpServlet {
    
    private String instanceMessage;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
        String message = request.getParameter("message");
        instanceMessage = request.getParameter("message");
        request.setAttribute("text", message);
        request.setAttribute("unsafeText", instanceMessage);
        request.getRequestDispatcher("/jsp/ExampleThree.jsp").forward(request, response);
    }
}

在本例中,會話中的所有請求共享 instanceMessage,而 message對於給定的請求物件是唯一的。因此,在併發請求的情況下,instanceMessage 中的資料可能不一致。

6. 總結

在本教程中,我們探討了有關servlet的一些概念、它們的容器以及它們所圍繞的一些基本物件,以及 servlet 如何共享資料和多執行緒如何影響它們.

如果你覺得文章還不錯,記得關注公眾號: 鍋外的大佬
鍋外的大佬部落格

相關文章