Java Servlet 工作原理問答
導讀
本文來自stackoverflow的問答,討論了Java Servlet的工作機制,如何進行例項化、共享變數和多執行緒處理。
問題:Servlet是如何工作的?Servlet 如何例項化、共享變數、並進行多執行緒處理?
假設我有一個執行了大量 Servlet
的 web 伺服器。通過 Servlet
之間傳輸資訊得到 Servlet
上下文,並設定 session 變數。
現在,如果有兩名或更多使用者向這個服務傳送請求,接下來 session 變數會發生什麼變化?究竟是所有使用者都是用共同的變數?還是不同的使用者使用的變數都不一樣?如果是後者,伺服器如何區分不同使用者?
另一個相似的問題,如果有 *n*
名使用者訪問一個特定的 Servlet
,那麼該 Servlet
是僅在第一個使用者首次訪問的時候例項化,還是分別為每個使用者例項化?
回答(BalusC):
ServletContext
當 Servlet 容器(比如 Apache Tomcat)啟動後,會部署和載入所有 web 應用。當web 應用被載入,Servlet 容器會建立一次 ServletContext
,然後將其儲存在伺服器的記憶體中。web 應用的 web.xml
被解析,找到其中所有 servlet
、filter
和 Listener
或 @WebServlet
、@WebFilter
和 @WebListener
註解的內容,建立一次並儲存到伺服器的記憶體中。對於所有過濾器會立即呼叫 init()
。當 Servlet 容器停止,將解除安裝所有 web 應用,呼叫所有初始化的 Servlet 和過濾器的 destroy()
方法,最後回收 ServletContext
和所有 Servlet
、Filter 與 Listener
例項。
當問題中的 Servlet
配置的 load-on-startup
或者 @WebServlet(loadOnStartup)
設定了一個大於 0 的值,則同樣會在啟動的時候立即呼叫 init()
方法。“load-on-startup”中的值表示那些 Servlet 會以相同順序初始化。如果配置的值相同,會遵循 web.xml
中指定的順序或 @WebServlet
類載入的順序。另外,如果不設定 “load-on-startup” 值,init()
方法只在第一次 HTTP 請求命中問題中的 Servlet 時才被呼叫。
HttpServletRequest 與 HttpServletResponse
Servlet 容器附加在一個 web 服務上,這個 web 服務會在某個埠號上監聽 HTTP 請求,在開發環境中這個埠通常為 8080,生產環境中通常為 80。當客戶端(web 瀏覽器)傳送了一個 HTTP 請求,Servlet 容器會建立新的 HttpServletRequest
和 HttpServletResponse
物件,傳遞給已建立好並且請求的 URL 匹配 url-pattern
的 Filter
和 Servlet
例項中的方法,所有工作都在同一個執行緒中處理。
request 物件可以訪問所有該 HTTP 請求中的資訊,例如 request header 和 request body。response 物件為你提供需要的控制和傳送 HTTP 響應方法,例如設定 header 和 body(通常會帶有 JSP 檔案中的 HTML 內容)。提交併完成HTTP 響應後,將回收 request 和 response 物件。
HttpSession
當使用者第一次訪問該 web 應用時,會通過 request.getSession()
第一次獲得 HttpSession。之後 Servlet 容器將會建立 HttpSession
,生成一個唯一的 ID(可以通過 session.getId()
獲取)並儲存在伺服器記憶體中。然後 Servlet 容器在該次 HTTP 響應的 Set-Cookie
頭部設定一個 Cookie
,以 JSESSIONID
作為 Cookie 名字,那個唯一的 session ID 作為 Cookie
的值。
按照 HTTP cookie 規則(正常 web 瀏覽器和 web 服務端必須遵循的標準),當 cookie 有效時,要求客戶端(瀏覽器)在後續請求的 Cookie
頭中返回這個 cookie。使用瀏覽器內建的 HTTP 流量監控器,你可以檢視它們(在 Chrome、Firefox23+、IE9+ 中按 F12,然後檢視 Net/Network 標籤)。Servlet 容器將會確定每個進入的 HTTP 請求的 Cookie
頭中是否存在名為JSESSIONID
的 cookie,然後用它的值(session ID)從服務端記憶體中找到關聯的 HttpSession
。
你可以在 web.xml
中設定 session-timeout
,預設值為 30 分鐘。超時到達之前 HttpSession
會一直存活。所以當客戶端不再訪問該 web 應用超過 30 分鐘後,Servlet 容器就會回收這個 session。後續每個請求,即使指定 cookie 名稱也不能再訪問到相同的 session。Servlet 容器會建立一個新的 Cookie
。
另一方面,客戶端上的 session cookie 有一個預設存活時間,該事件和該瀏覽器例項執行時間一樣長。所以,當客戶端關閉該瀏覽器例項(所有標籤和視窗)後,這個 session 就會被客戶端回收。新瀏覽器例項不再傳送與該 session 關聯的 cookie。一個新的 request.getSession()
將會返回新的 HttpSession
並設定一個擁有新 session
ID 的 cookie。
概述
ServletContext
與 web 應用存活時間一樣長。它被所有 session 中的所有請求共享。- 只要客戶端一直與相同瀏覽器例項的web應用互動並且沒有超時,HttpSession就會存在。
HttpServletRequest
和HttpServletResponse
的存活時間為客戶端傳送完成到完整的響應(web 頁面)到達的這段時間。不會被其他地方共享。所有 Servlet
、Filter
和Listener
物件在 web 應用執行時都是活躍的。它們被所有 session 中的請求共享。- 你設定在
HttpServletRequest
、HttpServletResponse
和HttpSession
中的所有屬性在問題中的物件存活時都會一直保持存活。
執行緒安全
即便如此,你最關心的可能是執行緒安全。你現在應該學習到 Servlet 和 filter 被所有請求共享。那是 Java 的一個優點,使得多個不同執行緒(讀取 HTTP 請求)可以使用同一個例項。否則為每個請求重新建立執行緒的開銷實在過於昂貴。
但你應該也意識到永遠不要將任何 request 或 session 域中的資料賦值給 servlet 或 filter 的例項變數。它將會被所有其他 session 中的所有請求共享。那是非執行緒安全的!下面的示例對這種情況進行了展示:
public class ExampleServlet extends HttpServlet { private Object thisIsNOTThreadSafe; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object thisIsThreadSafe; thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. } }
請參考:
相關文章
- 問答丨如何理解雜湊表的工作原理?
- 技術問答集錦(13)Java Instrument原理Java
- servlet的生命週期和工作原理介紹Servlet
- Servlet系列:(一)servlet原理剖析Servlet
- Servlet 如何工作Servlet
- 走進JavaWeb技術世界4:Servlet 工作原理詳解JavaWebServlet
- JAVA容器-自問自答學LinkedListJava
- Java之ServletJavaServlet
- 百問百答第41期:應用效能探針監測原理-Java探針Java
- 八問八答搞懂Transformer內部運作原理ORM
- 冴羽答讀者問:怎麼平衡工作與生活?
- 【Java基礎】ServletJavaServlet
- java面試題-HashMap的工作原理Java面試題HashMap
- 社群問答精選|ChatGPT for SegmentFault 十問十答ChatGPT
- java Servlet結構概述JavaServlet
- java servlet 生命週期JavaServlet
- Java中Servlet技術JavaServlet
- HashMap中面試常問的工作原理HashMap面試
- JAVAEE_Servlet_24_HttpSession實現原理JavaServletHTTPSession
- 提問與問答技巧
- 基礎問答
- 問答專案
- 【計題04組01號】Java面試問答題Java面試
- 免費OA工作流實際應用中的問與答
- Java JUnit框架裡@Category註解的工作原理Java框架Go
- Java 多執行緒 | 併發知識問答總結Java執行緒
- 面試問你java中的序列化怎麼答?面試Java
- Web 面試問答Web面試
- 百問百答第42期:應用效能探針監測原理-.net
- PostgreSQL的AutoVacuum原理及autovacuum不工作問題解析SQL
- Java Web(5)-Servlet詳解(下)JavaWebServlet
- Java Web(5)-Servlet詳解(上)JavaWebServlet
- Java-Servlet知識總結JavaServlet
- java EE開發之Servlet第一課:servlet的建立方式JavaServlet
- java EE開發之Servlet第二課:Servlet的三個hashMapJavaServletHashMap
- JAVA網路程式設計基本功之Servlet與Servlet容器Java程式設計Servlet
- 老牌問答網站“雅虎問答”近日宣佈正式關站NRE網站
- Java資深工程師面試之chatGPT自問自答版Java工程師面試ChatGPT
- Nginx工作原理Nginx