天天看點

Servlet 如何工作

我們已經清楚了 Servlet 是如何被加載的、初始化及其體系結構,現在的問題就是它是如何被調用的.

使用者從浏覽器向伺服器發起的一個請求通常會包含如下資訊

http://hostname: port /contextpath/servletpath

  • hostname 和 port:與伺服器建立 TCP 連接配接
  • URL:選擇在伺服器中哪個子容器服務使用者的請求

伺服器是如何根據這個 URL 到達正确的 Servlet 容器中的呢?

  • 在 Tomcat7 中這件事很容易解決,因為這種映射工作有專門的一個類來完成 org.apache.tomcat.util.http.mapper.

    該類儲存了 Tomcat 的 Container 容器中所有子容器的資訊.

    在org.apache.catalina.connector.Request 類進入 Container 容器之前,mapper 會根據這次請求的

    hostnane

    contextpath

    host

    context 容器

    設定到 Request 的 mappingData 屬性中,如下圖所示.

    是以當 Request進入 Container 容器之前,它要通路哪個子容器就已經确定了.

    Servlet 如何工作
    Request 的 Mapper 類關系圖

可能你有疑問,mapper 中怎麼會有容器的完整關系?

這要回到

http://upload-images.jianshu.io/upload_images/4685968-f4c4cc6126fe8e14.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700

中 第 19 步 MapperListener 類的初始化過程,下面是其的init 方法代碼

public void init() { 
        findDefaultHost(); 
        Engine engine = (Engine) connector.getService().getContainer(); 
        engine.addContainerListener(this); 
        Container[] conHosts = engine.findChildren(); 
        for (Container conHost : conHosts) { 
            Host host = (Host) conHost; 
            if (!LifecycleState.NEW.equals(host.getState())) { 
                host.addLifecycleListener(this); 
                registerHost(host); 
            } 
        } 
 }
           

這段代碼的作用就是将 MapperListener 作為一個監聽者加到整個 Container 容器的每個子容器中.

如此,任何一個容器發生變化,MapperListener 都将會被通知到,相應的儲存容器關系的 MapperListener 的 mapper 屬性也會被修改.

在for 循環中就是将 host 及下面的子容器注冊到 mapper 中.

Servlet 如何工作

Request 在容器中的路由圖

上圖描述了一次 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 方法将被調用,善後.

繼續閱讀