Servlet與Tomcat的關(guān)系

  1. Servlet 工作原理解析:https://www.ibm.com/developerworks/cn/java/j-lo-servlet/
  2. JSP九大內(nèi)置對(duì)象的作用和用法總結(jié)?http://blog.csdn.net/sona_shi555/article/details/7797068
  3. Servlet簡(jiǎn)介與Servlet和HttpServlet運(yùn)行的流程:https://www.cnblogs.com/libingbin/p/5960456.html

servlet是什么?

Servlet是用Java編寫的Server端程序,它與協(xié)議和平臺(tái)無(wú)關(guān)。
Servlet運(yùn)行于Java-enabled Web Server中。
Java Servlet可以動(dòng)態(tài)地?cái)U(kuò)展Server的能力,并采用請(qǐng)求-響應(yīng)模式提供Web服務(wù)。
最早支持Servlet技術(shù)的是JavaSoft的Java Web Server。
此后,一些其它的基于Java的Web Server開(kāi)始支持標(biāo)準(zhǔn)的Servlet API。
Servlet的主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動(dòng)態(tài)Web內(nèi)容。

Servlet 與 Servlet 容器的關(guān)系

image.png

要介紹 Servlet 必須要先把 Servlet 容器說(shuō)清楚,Servlet 與 Servlet 容器的關(guān)系有點(diǎn)像槍和子彈的關(guān)系,槍是為子彈而生,而子彈又讓槍有了殺傷力。雖然它們是彼此依存的,但是又相互獨(dú)立發(fā)展,這一切都是為了適應(yīng)工業(yè)化生產(chǎn)的結(jié)果。從技術(shù)角度來(lái)說(shuō)是為了解耦,通過(guò)標(biāo)準(zhǔn)化接口來(lái)相互協(xié)作。既然接口是連接 Servlet 與 Servlet 容器的關(guān)鍵,那我們就從它們的接口說(shuō)起。
(1)Context 容器
Tomcat 的容器等級(jí)中,Context 容器是直接管理 Servlet 在容器中的包裝類 Wrapper,所以 Context 容器如何運(yùn)行將直接影響 Servlet 的工作方式。

真正管理 Servlet 的容器是 Context 容器,一個(gè) Context 對(duì)應(yīng)一個(gè) Web 工程,在 Tomcat 的配置文件中可以很容易發(fā)現(xiàn)這一點(diǎn),如下:

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

(2)Servlet 容器的啟動(dòng)過(guò)程
Tomcat7 也開(kāi)始支持嵌入式功能,增加了一個(gè)【啟動(dòng)類 org.apache.catalina.startup.Tomcat】。創(chuàng)建一個(gè)實(shí)例對(duì)象并調(diào)用 start 方法就可以很容易啟動(dòng) Tomcat,我們還可以通過(guò)這個(gè)對(duì)象來(lái)增加和修改 Tomcat 的配置參數(shù),如可以動(dòng)態(tài)增加 Context、Servlet 等。我們就選擇 Tomcat7 自帶的 examples Web 工程,并看看它是如何加到這個(gè) Context 容器中的。

清單 1:給 Tomcat 增加一個(gè) 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的代碼是創(chuàng)建一個(gè) Tomcat 實(shí)例并新增一個(gè) Web 應(yīng)用,然后啟動(dòng) Tomcat 并調(diào)用其中的一個(gè) HelloWorldExample Servlet,看有沒(méi)有正確返回預(yù)期的數(shù)據(jù)。

清單 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; 
}

添加一個(gè) Web 應(yīng)用時(shí)將會(huì)創(chuàng)建一個(gè) StandardContext 容器,并且給這個(gè) Context 容器設(shè)置必要的參數(shù)(
url 代表這個(gè)應(yīng)用在 Tomcat 中的訪問(wèn)路徑;
path 代表這個(gè)應(yīng)用實(shí)際的物理路徑)
其中最重要的一個(gè)配置是 ContextConfig,【ContextConfig監(jiān)聽(tīng)器】繼承了 【LifecycleListener 監(jiān)聽(tīng)器接口】,它是在調(diào)用清單 2 時(shí)被加入到 StandardContext 容器中。
當(dāng) Context 容器初始化狀態(tài)設(shè)為 init 時(shí),添加在 Context 容器的 Listener 將會(huì)被調(diào)用?!綜ontextConfig監(jiān)聽(tīng)器】將會(huì)負(fù)責(zé)整個(gè) Web 應(yīng)用配置文件的解析工作。
最后將這個(gè) Context 容器加到父容器 Host 中。

(3)【ContextConfig監(jiān)聽(tīng)器】的解析工作有哪些?
ContextConfig 的 init 方法將會(huì)主要完成以下工作:
1.創(chuàng)建用于解析 xml 配置文件的 contextDigester 對(duì)象
1.讀取默認(rèn) context.xml 配置文件,如果存在解析它
1.讀取默認(rèn) Host 配置文件,如果存在解析它
1.讀取默認(rèn) Context 自身的配置文件,如果存在解析它
1.設(shè)置 Context 的 DocBase
ContextConfig 的 init 方法完成后,Context 容器的會(huì)執(zhí)行 startInternal 方法,這個(gè)方法啟動(dòng)邏輯比較復(fù)雜,主要包括如下幾個(gè)部分:
1.創(chuàng)建讀取資源文件的對(duì)象
1.創(chuàng)建 ClassLoader 對(duì)象
1.設(shè)置應(yīng)用的工作目錄
1.啟動(dòng)相關(guān)的輔助類如:logger、realm、resources 等
1.修改啟動(dòng)狀態(tài),通知感興趣的觀察者(Web 應(yīng)用的配置)
1.子容器的初始化
1.獲取 ServletContext 并設(shè)置必要的參數(shù)
1.初始化“l(fā)oad on startup”的 Servlet

(4)Web 應(yīng)用的初始化工作?
應(yīng)用的初始化主要是要解析 web.xml 文件,這個(gè)文件描述了一個(gè) Web 應(yīng)用的關(guān)鍵信息,也是一個(gè) Web 應(yīng)用的入口。
【web.xml 文件】中的各個(gè)配置項(xiàng)將會(huì)被解析成相應(yīng)的屬性保存在 【W(wǎng)ebXml 對(duì)象】中。
接下去將會(huì)將 WebXml 對(duì)象中的屬性設(shè)置到 Context 容器中,這里包括創(chuàng)建 Servlet 對(duì)象、filter、listener 等等,這些代碼在 WebXml 的 configureContext 方法中。

(5)servlet 與 wrapper 的關(guān)系?
Servlet 被 【解析】 和 【包裝】 成 【Context 容器中的 StandardWrapper】。
這里有個(gè)疑問(wèn),為什么要將 Servlet 包裝成 StandardWrapper 而不直接是 Servlet 對(duì)象。
這里 StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 為了一個(gè)獨(dú)立的 web 開(kāi)發(fā)標(biāo)準(zhǔn),不應(yīng)該強(qiáng)耦合在 Tomcat 中。


image.png

Servlet 體系結(jié)構(gòu)

image.png

與 Servlet 主動(dòng)關(guān)聯(lián)的是三個(gè)頂層類,分別是 【ServletConfig】、【ServletRequest】 和 【ServletResponse】。這三個(gè)類都是通過(guò)容器傳遞給 Servlet 的。
(1)Servlet 的運(yùn)行模式是一個(gè)典型的“握手型的交互式”運(yùn)行模式。所謂“握手型的交互式”就是兩個(gè)模塊為了交換數(shù)據(jù)通常都會(huì)準(zhǔn)備一個(gè)【交易場(chǎng)景】,這個(gè)場(chǎng)景一直跟隨著這個(gè)交易過(guò)程直到這個(gè)交易完成為止。這個(gè)交易場(chǎng)景的初始化是根據(jù)這次【交易對(duì)象指定的參數(shù)來(lái)】定制的,這些指定參數(shù)通常就會(huì)是一個(gè)【配置類】。
(1)ServletConfig 接口的作用:獲取這個(gè) Servlet 的一些【配置類】屬性。
(2)【ServletContext頂層類】的作用:是一個(gè)描述【交易場(chǎng)景】的【參數(shù)集合】即【配置類】。

Tomcat 創(chuàng)建的 Request 和 Response 類

image.png

1.Tomcat 一接受到請(qǐng)求首先將會(huì)創(chuàng)建 【org.apache.coyote.Request】 和 【org.apache.coyote.Response】,這兩個(gè)類是 Tomcat 內(nèi)部使用的描述一次請(qǐng)求和相應(yīng)的信息類它們是一個(gè)輕量級(jí)的類,它們作用就是在服務(wù)器接收到請(qǐng)求后,經(jīng)過(guò)簡(jiǎn)單解析將這個(gè)請(qǐng)求快速的分配給后續(xù)線程去處理,所以它們的對(duì)象很小,很容易被 JVM 回收。
2.接下去當(dāng)交給一個(gè)用戶線程去處理這個(gè)請(qǐng)求時(shí)又創(chuàng)建 【org.apache.catalina.connector.Request】 和 【org.apache.catalina.connector.Response】 對(duì)象。這兩個(gè)對(duì)象一直穿越整個(gè) Servlet 容器,直到要傳給 Servlet。
3.傳給 Servlet 的是 Request 和 Response 的【門面類】 【RequestFacade】 和 【ResponseFacade】,這里使用【門面模式】的目的——【封裝容器中的數(shù)據(jù)】。

Servlet 如何工作?

當(dāng)用戶從瀏覽器向服務(wù)器發(fā)起一個(gè)請(qǐng)求,通常會(huì)包含如下信息:【http://hostname: port /contextpath/servletpath】。
hostname 和 port 是用來(lái)與服務(wù)器建立 TCP 連接。
而后面的【/contextpath/servletpath】即【 URL 】才是用來(lái)選擇服務(wù)器中的哪個(gè)子容器來(lái)服務(wù)用戶的請(qǐng)求。
Tomcat7.0 中有個(gè)映射類【org.apache.tomcat.util.http.mapper】,這個(gè)類保存了 Tomcat 的 Container 容器中的所有子容器的信息,
mapper 將會(huì)根據(jù)這次請(qǐng)求的 hostnane 和 contextpath 將 host 和 context 容器設(shè)置到 Request 的 mappingData 屬性中。

Session

(1)Session的三種工作方式
1.基于 URL Path Parameter,默認(rèn)就支持;
1.基于 Cookie,如果你沒(méi)有修改 Context 容器和 cookies 標(biāo)識(shí)的話,默認(rèn)也是支持的;
1.基于 SSL,默認(rèn)不支持,只有 connector.getAttribute(“SSLEnabled”) 為 TRUE 時(shí)才支持。
(2)SSL(Secure Sockets Layer 安全套接層)協(xié)議,及其繼任者TLS(Transport Layer Security傳輸層安全)協(xié)議,是為網(wǎng)絡(luò)通信提供安全及數(shù)據(jù)完整性的一種安全協(xié)議。TLS與SSL在傳輸層對(duì)網(wǎng)絡(luò)連接進(jìn)行加密,用于保障網(wǎng)絡(luò)數(shù)據(jù)傳輸安全,利用數(shù)據(jù)加密技術(shù),確保數(shù)據(jù)在網(wǎng)絡(luò)傳輸過(guò)程中不會(huì)被截取及竊聽(tīng)。SSL協(xié)議已成為全球化標(biāo)準(zhǔn),所有主要的瀏覽器和WEB服務(wù)器程序都支持SSL協(xié)議,可通過(guò)安裝SSL證書激活SSL協(xié)議。
SSL 證書就是遵守 SSL協(xié)議的服務(wù)器數(shù)字證書,由受信任的證書頒發(fā)機(jī)構(gòu)(CA機(jī)構(gòu)),驗(yàn)證服務(wù)器身份后頒發(fā),部署在服務(wù)器上,具有網(wǎng)站身份驗(yàn)證和加密傳輸雙重功能。
如果是第三種情況的話將會(huì)根據(jù) javax.servlet.request.ssl_session 屬性值設(shè)置 Session ID。
(3)有了 Session ID 服務(wù)器端就可以創(chuàng)建 HttpSession 對(duì)象了,第一次觸發(fā)是通過(guò) request. getSession() 方法,如果當(dāng)前的 Session ID 還沒(méi)有對(duì)應(yīng)的 HttpSession 對(duì)象那么就創(chuàng)建一個(gè)新的,并將這個(gè)對(duì)象加到 org.apache.catalina. Manager 的 sessions 容器中保存,Manager 類將管理所有 Session 的生命周期,Session 過(guò)期將被回收,服務(wù)器關(guān)閉,Session 將被序列化到磁盤等。只要這個(gè) HttpSession 對(duì)象存在,用戶就可以根據(jù) Session ID 來(lái)獲取到這個(gè)對(duì)象,也就達(dá)到了狀態(tài)的保持。
(4)Session 的致命弱點(diǎn)是不容易在多臺(tái)服務(wù)器之間共享。

Servlet 中的 Listener

(1)整個(gè) Tomcat 服務(wù)器中 Listener 使用的非常廣泛,它是基于【觀察者模式】設(shè)計(jì)的。
Listener 的設(shè)計(jì)對(duì)開(kāi)發(fā) Servlet 應(yīng)用程序提供了一種快捷的手段,能夠方便的從另一個(gè)【縱向維度控制程序和數(shù)據(jù)】。
(2)目前 Servlet 中提供了 6 種兩類事件的觀察者接口,它們分別是:
4 個(gè) EventListeners 類型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 個(gè) LifecycleListeners 類型的,ServletContextListener、HttpSessionListener。
這些 Listener 的實(shí)現(xiàn)類可以配置在 web.xml 中的 標(biāo)簽中。當(dāng)然也可以在應(yīng)用程序中動(dòng)態(tài)添加 Listener,需要注意的是 ServletContextListener 在容器啟動(dòng)之后就不能再添加新的,因?yàn)樗O(jiān)聽(tīng)的事件已經(jīng)不會(huì)再出現(xiàn)。掌握這些 Listener 的使用,能夠讓我們的程序設(shè)計(jì)的更加靈活。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容