在這篇簡短的文章中,咱們將從概念上理解什麼是servlet
和 servlet
容器以及它們是如何工做的。
同時,還能在請求、響應、會話對象、共享變量和多線程的上下文中看到它們的身影。java
servlet
是 JEE
用於 web
開發經常使用的組件。它們基本上是運行在容器邊界內的Java程序。總的來講,它們負責接受請求,處理請求,並返回響應。web
要使用它們,首先須要容器註冊 servlet
,不管是基於 JEE
仍是基於 Spring
的容器,均可以在啓動時接收它們。在開始時,容器經過調用 init() 方法來實例化 servlet
。
初始化完成後,servlet
就能夠接受傳入的請求。隨後,容器將這些請求定向到 servlet
的 service
方法中進行處理。以後,它根據HTTP請求類型將請求進一步委託給適當的方法,例如 doGet()
或 doPost()
。瀏覽器
使用 destroy()
,容器會銷燬 servlet
,而且再也不接受傳入的請求。咱們將這個 init-service-destroy
的循環稱爲 servlet
的生命週期。安全
如今咱們從容器的角度來看,好比 Apache Tomcat
或 Jetty
在啓動時,建立一個 ServletContext 的對象,ServletContext 的任務是充當服務器或容器的內存,並記住與web應用程序相關聯的全部servlet、過濾器和偵聽器,如其 web.xml文件或等效註解。在容器中止以前,ServletContext 會一直保留它。服務器
無論怎麼說,servlet
的 load-on-startup
參數扮演重要的角色 。若是此參數的值大於零,則只有在啓動時服務器纔會對其進行初始化。若是未指定此參數,則在請求第一次命中 servlet
時調用它的 init()。
cookie
在上一節中,咱們討論了發送請求和接收響應,這基本上是任何CS應用程序的基礎。如今,咱們從servlet
的角度來詳細瞭解它們。session
在這種狀況下,請求將由 HttpServletRequest
表示,響應將用 HttpServletResponse
表示。多線程
每當瀏覽器或curl命令等發送請求時,容器都會建立一個新的 HttpServletRequest
和 HttpServletResponse
對象。而後將這些新對象傳遞給 servlet
的 service
方法。基於 HttpServletRequest
的 method
屬性,此方法肯定應調用哪一個 doXXX
方法。併發
除了有關方法的信息外,request對象還攜帶其餘信息,如頭、參數和主體。相似地,HttpServletResponse
對象也攜帶頭、參數和主體——咱們能夠在 servlet
的 doXXX
方法中設置它們。curl
這些對象的生命稍縱即逝。當客戶端得到響應時,服務器將標記用於垃圾回收的請求和響應對象。
那麼咱們如何在隨後的客戶端請求或鏈接之間保持一個狀態?答案就是 HttpSession
。
原理是將這些對象綁定到用戶會話,以便與特定用戶相關的信息能夠跨多個請求持久化。這一般是經過使用cookies的概念,使用 [JSESSIONID] 做爲給定會話的惟一標識符。咱們能夠在web.xml中指定會話的超時時長。
<session-config> <session-timeout>10</session-timeout> </session-config>
以上配置表示,若是會話空閒了10分鐘,服務器將丟棄它。任何後續請求都將建立一個新的會話。
根據所需的範圍,servlet
能夠經過多種方式共享數據。
正如在前面的章節中提到的,不一樣的對象有不一樣的生命週期。HttpServletRequest
和HttpServletResponse
對象只存在於一個 servlet
調用之間。HttpSession
只要它處於活動狀態而且沒有超時,它就會一直存在。
ServletContext
的生命週期最長。它與Web應用程序一塊兒誕生,只有當應用程序自己關閉時纔會被銷燬。因爲servlet、filter 和 listener 實例與上下文綁定,因此只要web應用程序啓動並運行,它們也會一直存在。
所以,若是咱們的需求是在全部servlet之間共享數據,假設咱們要計算站點的訪問者數量,那麼咱們應該將變量放在 ServletContext 中。若是咱們須要在一個會話中共享數據,那麼咱們就把它保存在會話範圍內。在本例中,用戶名就是一個例子。
最後,還有與單個請求的數據相關的請求範圍,好比請求有效負載。
多個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 中的數據可能不一致。
在本教程中,咱們探討了有關servlet的一些概念、它們的容器以及它們所圍繞的一些基本對象,以及 servlet 如何共享數據和多線程如何影響它們.
若是你以爲文章還不錯,記得關注公衆號: 鍋外的大佬
鍋外的大佬博客