超詳細 Servlet工作原理解析
上圖描述了一次 Request 請求是如何達到最終的 Wrapper 容器的,我們現正知道了請求是如何達到正確的 Wrapper容器,但是請求到達最終的 Servlet 還要完成一些步驟,必須要執行 Filter 鏈,以及要通知你在 web.xml 中定義的listener。
接下去就要執行 Servlet 的 service 方法了,通常情況下,我們自己定義的 servlet 並不是直接去實現javax.servlet.servlet 介面,而是去繼承更簡單的 HttpServlet 類或者 GenericServlet類,我們可以有選擇的覆蓋相應方法去實現我們要完成的工作。
Servlet 的確已經能夠幫我們完成所有的工作了,但是現在的 web 應用很少有直接將互動全部頁面都用 servlet來實現,而是採用更加高效的 MVC 框架來實現。這些 MVC 框架基本的原理都是將所有的請求都對映到一個 Servlet,然後去實現service 方法,這個方法也就是 MVC 框架的入口。
當 Servlet 從 Servlet 容器中移除時,也就表明該 Servlet 的生命週期結束了,這時 Servlet 的destroy 方法將被呼叫,做一些掃尾工作。
——————————————————————————————————————————
Session 與 Cookie
前面我們已經說明了 Servlet 如何被呼叫,我們基於 Servlet 來構建應用程式,那麼我們能從 Servlet獲得哪些資料資訊呢?
Servlet 能夠給我們提供兩部分資料,一個是在 Servlet 初始化時呼叫 init 方法時設定的ServletConfig,這個類基本上含有了 Servlet 本身和 Servlet 所執行的 Servlet容器中的基本資訊。根據前面的介紹 ServletConfig 的實際物件是StandardWrapperFacade,到底能獲得哪些容器資訊可以看看這類提供了哪些介面。還有一部分資料是由ServletRequest 類提供,它的實際物件是 RequestFacade,從提供的方法中發現主要是描述這次請求的 HTTP協議的資訊。所以要掌握 Servlet 的工作方式必須要很清楚 HTTP協議,如果你還不清楚趕緊去找一些參考資料。關於這一塊還有一個讓很多人迷惑的 Session 與 Cookie。
Session 與 Cookie 不管是對 Java Web 的熟練使用者還是初學者來說都是一個令人頭疼的東西。Session 與Cookie的作用都是為了保持訪問使用者與後端伺服器的互動狀態。它們有各自的優點也有各自的缺陷。然而具有諷刺意味的是它們優點和它們的使用場景又是矛盾的,例如使用Cookie 來傳遞資訊時,隨著 Cookie 個數的增多和訪問量的增加,它佔用的網路頻寬也很大,試想假如 Cookie 佔用 200個位元組,如果一天的 PV 有幾億的時候,它要佔用多少頻寬。所以大訪問量的時候希望用 Session,但是 Session的致命弱點是不容易在多臺伺服器之間共享,所以這也限制了 Session 的使用。
不管 Session 和 Cookie 有什麼不足,我們還是要用它們。下面詳細講一下,Session 如何基於 Cookie來工作。實際上有三種方式能可以讓 Session 正常工作:
- 基於 URL Path Parameter,預設就支援
- 基於 Cookie,如果你沒有修改 Context 容器個 cookies 標識的話,預設也是支援的
- 基於 SSL,預設不支援,只有 connector.getAttribute("SSLEnabled") 為 TRUE時才支援
第一種情況下,當瀏覽器不支援 Cookie 功能時,瀏覽器會將使用者的 SessionCookieName 重寫到使用者請求的 URL引數中,它的傳遞格式如 /path/Servlet;name=value;name2=value2?Name3=value3,其中“Servlet;”後面的 K-V 對就是要傳遞的 Path Parameters,伺服器會從這個Path Parameters 中拿到使用者配置的 SessionCookieName。關於這個SessionCookieName,如果你在 web.xml 中配置 session-config 配置項的話,其cookie-config 下的 name 屬性就是這個 SessionCookieName 值,如果你沒有配置session-config 配置項,預設的 SessionCookieName 就是大家熟悉的“JSESSIONID”。接著Request 根據這個 SessionCookieName 到 Parameters 拿到 Session ID 並設定到request.setRequestedSessionId 中。
請注意如果客戶端也支援 Cookie 的話,Tomcat 仍然會解析 Cookie 中的 Session ID,並會覆蓋 URL 中的Session ID。
如果是第三種情況的話將會根據 javax.servlet.request.ssl_session 屬性值設定 SessionID。
有了 Session ID 伺服器端就可以建立 HttpSession 物件了,第一次觸發是通過 request.getSession() 方法,如果當前的 Session ID 還沒有對應的 HttpSession物件那麼就建立一個新的,並將這個物件加到 org.apache.catalina. Manager 的 sessions容器中儲存,Manager 類將管理所有 Session 的生命週期,Session 過期將被回收,伺服器關閉,Session將被序列化到磁碟等。只要這個 HttpSession 物件存在,使用者就可以根據 Session ID來獲取到這個物件,也就達到了狀態的保持。