1. 程式人生 > >servlet與tomcat的關係

servlet與tomcat的關係

servlet是什麼?

Servlet是用Java編寫的Server端程式,它與協議和平臺無關。
Servlet運行於Java-enabled Web Server中。
Java Servlet可以動態地擴充套件Server的能力,並採用請求-響應模式提供Web服務。
最早支援Servlet技術的是JavaSoft的Java Web Server。
此後,一些其它的基於Java的Web Server開始支援標準的Servlet API。
Servlet的主要功能在於互動式地瀏覽和修改資料,生成動態Web內容。

Servlet 與 Servlet 容器的關係

tomcat容器模型
要介紹 Servlet 必須要先把 Servlet 容器說清楚,Servlet 與 Servlet 容器的關係有點像槍和子彈的關係,槍是為子彈而生,而子彈又讓槍有了殺傷力。雖然它們是彼此依存的,但是又相互獨立發展,這一切都是為了適應工業化生產的結果。從技術角度來說是為了解耦,通過標準化介面來相互協作。既然介面是連線 Servlet 與 Servlet 容器的關鍵,那我們就從它們的介面說起。
(1)Context 容器
Tomcat 的容器等級中,Context 容器是直接管理 Servlet 在容器中的包裝類 Wrapper,所以 Context 容器如何執行將直接影響 Servlet 的工作方式。

真正管理 Servlet 的容器是 Context 容器,一個 Context 對應一個 Web 工程,在 Tomcat 的配置檔案中可以很容易發現這一點,如下:

<Context path="/projectOne " docBase="D:\projects\projectOne"
reloadable="true" />

(2)Servlet 容器的啟動過程
Tomcat7 也開始支援嵌入式功能,增加了一個【啟動類 org.apache.catalina.startup.Tomcat】。建立一個例項物件並呼叫 start 方法就可以很容易啟動 Tomcat,我們還可以通過這個物件來增加和修改 Tomcat 的配置引數,如可以動態增加 Context、Servlet 等。我們就選擇 Tomcat7 自帶的 examples Web 工程,並看看它是如何加到這個 Context 容器中的。

清單 1:給 Tomcat 增加一個 Web 工程:
Tomcat tomcat = getTomcatInstance(); 
File appDir = new File(getBuildDirectory(), "webapps/examples"); 
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); 
tomcat.start(); 
ByteChunk res = getUrl("http://localhost:" + getPort() + 
              "/examples/servlets/servlet/HelloWorldExample"
); assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 0);

清單 1的程式碼是建立一個 Tomcat 例項並新增一個 Web 應用,然後啟動 Tomcat 並呼叫其中的一個 HelloWorldExample Servlet,看有沒有正確返回預期的資料。

清單 2:Tomcat 的 addWebapp 方法的程式碼如下:
public Context addWebapp(Host host, String url, String path) { 
       silence(url); 
       Context ctx = new StandardContext(); 
       ctx.setPath( url ); 
       ctx.setDocBase(path); 
       if (defaultRealm == null) { 
           initSimpleAuth(); 
       } 
       ctx.setRealm(defaultRealm); 
       ctx.addLifecycleListener(new DefaultWebXmlListener()); 
       ContextConfig ctxCfg = new ContextConfig(); 
       ctx.addLifecycleListener(ctxCfg); 
       ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML"); 
       if (host == null) { 
           getHost().addChild(ctx); 
       } else { 
           host.addChild(ctx); 
       } 
       return ctx; 
}

新增一個 Web 應用時將會建立一個 StandardContext 容器,並且給這個 Context 容器設定必要的引數(
url 代表這個應用在 Tomcat 中的訪問路徑;
path 代表這個應用實際的物理路徑)
其中最重要的一個配置是 ContextConfig,【ContextConfig監聽器】繼承了 【LifecycleListener 監聽器介面】,它是在呼叫清單 2 時被加入到 StandardContext 容器中。
當 Context 容器初始化狀態設為 init 時,新增在 Context 容器的 Listener 將會被呼叫。【ContextConfig監聽器】將會負責整個 Web 應用配置檔案的解析工作。
最後將這個 Context 容器加到父容器 Host 中。

(3)【ContextConfig監聽器】的解析工作有哪些?
ContextConfig 的 init 方法將會主要完成以下工作:
1.建立用於解析 xml 配置檔案的 contextDigester 物件
1.讀取預設 context.xml 配置檔案,如果存在解析它
1.讀取預設 Host 配置檔案,如果存在解析它
1.讀取預設 Context 自身的配置檔案,如果存在解析它
1.設定 Context 的 DocBase
ContextConfig 的 init 方法完成後,Context 容器的會執行 startInternal 方法,這個方法啟動邏輯比較複雜,主要包括如下幾個部分:
1.建立讀取資原始檔的物件
1.建立 ClassLoader 物件
1.設定應用的工作目錄
1.啟動相關的輔助類如:logger、realm、resources 等
1.修改啟動狀態,通知感興趣的觀察者(Web 應用的配置)
1.子容器的初始化
1.獲取 ServletContext 並設定必要的引數
1.初始化“load on startup”的 Servlet

(4)Web 應用的初始化工作?
應用的初始化主要是要解析 web.xml 檔案,這個檔案描述了一個 Web 應用的關鍵資訊,也是一個 Web 應用的入口。
【web.xml 檔案】中的各個配置項將會被解析成相應的屬性儲存在 【WebXml 物件】中。
接下去將會將 WebXml 物件中的屬性設定到 Context 容器中,這裡包括建立 Servlet 物件、filter、listener 等等,這些程式碼在 WebXml 的 configureContext 方法中。

(5)servlet 與 wrapper 的關係?
Servlet 被 【解析】 和 【包裝】 成 【Context 容器中的 StandardWrapper】。
這裡有個疑問,為什麼要將 Servlet 包裝成 StandardWrapper 而不直接是 Servlet 物件。
這裡 StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特徵,而 Servlet 為了一個獨立的 web 開發標準,不應該強耦合在 Tomcat 中。
ServletContext和ServletConfig與Wrapper的關係圖

Servlet 體系結構

Servlet 體系結構圖
與 Servlet 主動關聯的是三個頂層類,分別是 【ServletConfig】、【ServletRequest】 和 【ServletResponse】。這三個類都是通過容器傳遞給 Servlet 的。
(1)Servlet 的執行模式是一個典型的“握手型的互動式”執行模式。所謂“握手型的互動式”就是兩個模組為了交換資料通常都會準備一個【交易場景】,這個場景一直跟隨著這個交易過程直到這個交易完成為止。這個交易場景的初始化是根據這次【交易物件指定的引數來】定製的,這些指定引數通常就會是一個【配置類】。
(1)ServletConfig 介面的作用:獲取這個 Servlet 的一些【配置類】屬性。
(2)【ServletContext頂層類】的作用:是一個描述【交易場景】的【引數集合】即【配置類】。

Tomcat 建立的 Request 和 Response 類

tomcat的請求響應物件與servlet的請求響應物件的關係圖
1.Tomcat 一接受到請求首先將會建立 【org.apache.coyote.Request】 和 【org.apache.coyote.Response】,這兩個類是 Tomcat 內部使用的描述一次請求和相應的資訊類它們是一個輕量級的類,它們作用就是在伺服器接收到請求後,經過簡單解析將這個請求快速的分配給後續執行緒去處理,所以它們的物件很小,很容易被 JVM 回收。
2.接下去當交給一個使用者執行緒去處理這個請求時又建立 【org.apache.catalina.connector.Request】 和 【org.apache.catalina.connector.Response】 物件。這兩個物件一直穿越整個 Servlet 容器,直到要傳給 Servlet。
3.傳給 Servlet 的是 Request 和 Response 的【門面類】 【RequestFacade】 和 【RequestFacade】,這裡使用【門面模式】的目的——【封裝容器中的資料】。

Servlet 如何工作?

當用戶從瀏覽器向伺服器發起一個請求,通常會包含如下資訊:【http://hostname: port /contextpath/servletpath】。
hostname 和 port 是用來與伺服器建立 TCP 連線。
而後面的【/contextpath/servletpath】即【 URL 】才是用來選擇伺服器中的哪個子容器來服務使用者的請求。
Tomcat7.0 中有個對映類【org.apache.tomcat.util.http.mapper】,這個類儲存了 Tomcat 的 Container 容器中的所有子容器的資訊,
mapper 將會根據這次請求的 hostnane 和 contextpath 將 host 和 context 容器設定到 Request 的 mappingData 屬性中。

Session

(1)Session的三種工作方式
1.基於 URL Path Parameter,預設就支援;
1.基於 Cookie,如果你沒有修改 Context 容器個 cookies 標識的話,預設也是支援的;
1.基於 SSL,預設不支援,只有 connector.getAttribute(“SSLEnabled”) 為 TRUE 時才支援。
(2)SSL(Secure Sockets Layer 安全套接層)協議,及其繼任者TLS(Transport Layer Security傳輸層安全)協議,是為網路通訊提供安全及資料完整性的一種安全協議。TLS與SSL在傳輸層對網路連線進行加密,用於保障網路資料傳輸安全,利用資料加密技術,確保資料在網路傳輸過程中不會被擷取及竊聽。SSL協議已成為全球化標準,所有主要的瀏覽器和WEB伺服器程式都支援SSL協議,可通過安裝SSL證書啟用SSL協議。
SSL 證書就是遵守 SSL協議的伺服器數字證書,由受信任的證書頒發機構(CA機構),驗證伺服器身份後頒發,部署在伺服器上,具有網站身份驗證和加密傳輸雙重功能。
如果是第三種情況的話將會根據 javax.servlet.request.ssl_session 屬性值設定 Session ID。
(3)有了 Session ID 伺服器端就可以建立 HttpSession 物件了,第一次觸發是通過 request. getSession() 方法,如果當前的 Session ID 還沒有對應的 HttpSession 物件那麼就建立一個新的,並將這個物件加到 org.apache.catalina. Manager 的 sessions 容器中儲存,Manager 類將管理所有 Session 的生命週期,Session 過期將被回收,伺服器關閉,Session 將被序列化到磁碟等。只要這個 HttpSession 物件存在,使用者就可以根據 Session ID 來獲取到這個物件,也就達到了狀態的保持。
(4)Session 的致命弱點是不容易在多臺伺服器之間共享。

Servlet 中的 Listener

(1)整個 Tomcat 伺服器中 Listener 使用的非常廣泛,它是基於【觀察者模式】設計的。
Listener 的設計對開發 Servlet 應用程式提供了一種快捷的手段,能夠方便的從另一個【縱向維度控制程式和資料】。
(2)目前 Servlet 中提供了 6 種兩類事件的觀察者介面,它們分別是:
4 個 EventListeners 型別的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 個 LifecycleListeners 型別的,ServletContextListener、HttpSessionListener。
這些 Listener 的實現類可以配置在 web.xml 中的 標籤中。當然也可以在應用程式中動態新增 Listener,需要注意的是 ServletContextListener 在容器啟動之後就不能再新增新的,因為它所監聽的事件已經不會再出現。掌握這些 Listener 的使用,能夠讓我們的程式設計的更加靈活。