<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    TOMCAT源碼分析(消息處理)

    Posted on 2009-08-26 20:53 林光炎 閱讀(620) 評論(0)  編輯  收藏 所屬分類: JAVA
    :前言

    我們知道了tomcat的整體框架了, 也明白了里面都有些什么組件, 以及各個組件是干什么用的了。

    http://www.csdn.net/Develop/read_article.asp?id=27225

    我想,接下來我們應該去了解一下 tomcat 是如何處理jsp和servlet請求的。

    1.  我們以一個具體的例子,來跟蹤TOMCAT看看它是如何把Request一層一層地遞交給下一個容器,并最后交給Wrapper來處理的。

    http://localhost:8080/web/login.jsp為例子

    (以下例子,都是以tomcat4 源碼為參考)

    這篇心得主要分為3個部分: 前期, 中期, 和末期。

     前期:講解了在瀏覽器里面輸入一個URL,是怎么被tomcat抓住的。

    中期:講解了被tomcat抓住后,又是怎么在各個容器里面穿梭, 最后到達最后的處理地點。

    末期:講解到達最后的處理地點后,又是怎么具體處理的。

    2 前期 Request的born.

        在這里我先簡單講一下request這個東西。

         我們先看著這個URL:http://localhost:8080/web/login.jsp 它是動用了8080端口來進行socket通訊的。

         我們知道, 通過

           InputStream in = socket.getInputStream() 和

           OutputStream out = socket.getOutputStream()

         就可以實現消息的來來往往了。

         但是如果把Stream給應用層看,顯然操作起來不方便。

         所以,在tomcat 的Connector里面, socket被封裝成了Request和Response這兩個對象。

         我們可以簡單地把Request看成管發到服務器來的數據,把Response看成想發出服務器的數據。

         

         但是這樣又有其他問題了啊? Request這個對象是把socket封裝起來了, 但是他提供的又東西太多了。

         諸如Request.getAuthorization(), Request.getSocket()。 像Authorization這種東西開發人員拿來基本上用不太著,而像socket這種東西,暴露給開發人員又有潛在的危險。 而且啊, 在Servlet Specification里面標準的通信類是ServletRequest和HttpServletRequest,而非這個Request類。 So, So, So. Tomcat必須得搗持搗持Request才行。 最后tomcat選擇了使用搗持模式(應該叫適配器模式)來解決這個問題。它把org.apache.catalina.Request 搗持成了 org.apache.coyote.tomcat4.CoyoteRequest。 而CoyoteRequest又實現了ServletRequest和HttpServletRequest 這兩種接口。 這樣就提供給開發人員需要且剛剛需要的方法了。

     

        ok, 我們在 tomcat的頂層容器 - StandardEngin 的invoke()方法這里設置一個斷點, 然后訪問

        http://localhost:8080/web/login.jsp, 我們來看看在前期都會路過哪些地方:

           1. run(): 536, java.lang.Thread, Thread.java

           CurrentThread

          2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java

                   ThreadPool

           3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java

             ThreadWorker

    4.        processConnection():  549

    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java

                      http protocol parser

          5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java

              http request processor

           6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java

             adapter

           7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java

       StandardEngin

        1. 主線程

        2. 啟動線程池.

        3. 調出線程池里面空閑的工作線程。

        4. 把8080端口傳過來由httpd協議封裝的數據,解析成Request和Response對象。

        5. 使用Http11Processor來處理request

        6. 在Http11Processor里面, 又會call CoyoteAdapter來進行適配處理,把Request適配成實現了ServletRequest和HttpServletRequest接口的CoyoteRequest.

    7. 到了這里,前期的去毛拔皮工作就基本上搞定,可以交給StandardEngin 做核心的處理工作了。

    3. 中期。 在各個容器間的穿梭。

        Request在各個容器里面的穿梭大致是這樣一種方式:

        每個容器里面都有一個管道(pipline), 專門用來傳送Request用的。

        管道里面又有好幾個閥門(valve), 專門用來過濾Request用的。

        在管道的低部通常都會放上一個默認的閥們。 這個閥們至少會做一件事情,就是把Request交給子容器。

        讓我們來想象一下:

         當一個Request進入一個容器后, 它就在管道里面流動,波羅~ 波羅~ 波羅~ 地穿過各個閥門。在流到最后一個閥門的時候,吧唧~ 那個該死的閥門就把它扔給了子容器。 然后又開始 波羅~ 波羅~ 波羅~ ... 吧唧~.... 波羅~ 波羅~ 波羅~ ....吧唧~....

        就是通過這種方式, Request 走完了所有的容器。( 感覺有點像消化系統,最后一個地方有點像那里~ )

        OK, 讓我們具體看看都有些什么容器, 各個容器里面又都有些什么閥門,這些閥們都對我們的Request做了些什么吧:

    3.1 StandardEngin 的pipeline里面放的是:StandardEnginValve

    在這里,VALVE做了三件事:

    1.   驗證傳遞過來的request是不是httpservletRequest.

    2    驗證傳遞過來的 request 是否攜帶了host header信息.

    3    選擇相應的host去處理它。(一般我們都只有一個host:localhost,也就是127.0.0.1)。

    到了這個地方,我們的request就已經完成了在Engin這個部分的歷史使命,通向前途未卜的下一站: host了。

    3.2 StandardHost 的pipline里面放的是: StandardHostValve

    1.   驗證傳遞過來的request是不是httpservletRequest.

    2.   根據Request來確定哪個Context來處理。

    Context其實就是webapp比如http://localhost:8080/web/login.jsp

    這里web就是Context羅!

    3.   既然確定了是哪個Context了,那么就應該把那個Contextclassloader付給當前線程了。

            Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());

       這樣request就只看得見指定的context下面的classes啊, jar啊這些,而看不見tomcat本身的類,什么Engin啊, Valve啊。不然還得了啊!

    4. 既然request到了這里了,看來用戶是準備訪問web這個web app了,咋們得更新一下這個用戶的session不是! Ok , 就由manager更新一下用戶的session信息

    5. 交給具體的Context 容器去繼續處理Request.

    6. Context處理完畢了,把classloader還回來。

    3.3 StandardContext 的pipline里面放的是: StandardContextValve

    1.   驗證傳遞過來的request是不是httpservletRequest.

    2.   如果request意圖不軌,想要訪問/meta-inf, /web-inf這些目錄下的東西,呵呵,沒有用D!

    3.   這個時候就會根據Request到底是Servlet還是jsp還是靜態資源來決定到底用哪種Wrapper來處理這個Reqeust了。

    4.   一旦決定了到底用哪種WrapperOK,交給那個Wrapper處理。

    4. 末期。 不同的需求是怎么處理的.

    StandardWrapper

    之前對Wrapper沒有做過講解,其實它是這樣一種東西。

    我們在處理Request的時候,可以分成3種。

    處理靜態的: org.apache.catalina.servlets.DefaultServlet  

    處理jsp的:org.apache.jasper.servlet.JspServlet

    處理servlet的:org.apache.catalina.servlets.InvokerServlet

    不同的request就用這3種不同的servlet去處理。

    Wrapper就是對它們的一種簡單的封裝,有了Wrapper后,我們就可以輕松地攔截每次的Request。也可以容易地調用servlet的init()和destroy()方法, 便于管理嘛!

    具體情況是這么滴:

       如果request是找jsp文件,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.JspServlet去處理它。

       如果request是找 靜態資源 ,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.DefaultServlet 去處理它。

       如果request是找servlet ,StandardWrapper里面就會封裝一個org.apache.jasper.servlet.InvokerServlet 去處理它。

    StandardWrapper同樣也是容器,既然是容器, 那么里面一定留了一個管道給request去穿,管道低部肯定也有一個閥門(注1),用來做最后一道攔截工作.

    在這最底部的閥門里,其實就主要做了兩件事:

       一是啟動過濾器,讓request在N個過濾器里面篩一通,如果OK! 那就PASS。 否則就跳到其他地方去了。

       二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); 這個方法.

         如果是 JspServlet, 那么先把jsp文件編譯成servlet_xxx, 再invoke servlet_xxx的servie()方法。

         如果是 DefaultServlet, 就直接找到靜態資源,取出內容, 發送出去。

         如果是 InvokerServlet, 就調用那個具體的servlet的service()方法。

       ok! 完畢。

    注1: StandardWrapper 里面的閥門是最后一道關口了。 如果這個閥門欲意把request交給StandardWrapper 的子容器處理。 對不起, 在設計考慮的時候, Wrapper就被考慮成最末的一個容器, 壓根兒就不會給Wrapper添加子容器的機會! 如果硬是要調用addChild(), 立馬拋出IllegalArgumentException!

    參考:

         <http://jakarta.apache.org/tomcat/>
       <
    http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>

     


    相關文章

    posts - 104, comments - 33, trackbacks - 0, articles - 0

    Copyright © 林光炎

    主站蜘蛛池模板: 亚洲av无码专区在线播放| 日韩亚洲精品福利| 亚洲人成电影亚洲人成9999网| 美女黄频视频大全免费的| 日韩精品成人亚洲专区| 免费国产黄网站在线看| 亚洲国产一级在线观看| 国产人成网在线播放VA免费| 中文字幕亚洲激情| 成全高清在线观看免费| 情人伊人久久综合亚洲| 91香蕉国产线观看免费全集| 91亚洲国产成人精品下载| 国产成人精品久久免费动漫| 亚州**色毛片免费观看| 亚洲女人被黑人巨大进入| 91在线视频免费观看| 亚洲一级二级三级不卡| 日本最新免费网站| 亚洲色成人网站WWW永久四虎 | 亚洲免费中文字幕| 成年人网站在线免费观看| 亚洲精华国产精华精华液好用 | 91高清免费国产自产拍2021| 亚洲图片校园春色| 午夜无遮挡羞羞漫画免费| 无遮挡a级毛片免费看| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 亚洲中文字幕日本无线码| 小小影视日本动漫观看免费| av电影在线免费看| 亚洲色图综合网站| 国产又大又黑又粗免费视频| 中文字幕免费在线播放| 亚洲国产精品成人一区| 成人片黄网站色大片免费观看APP| 亚洲香蕉免费有线视频| 国产最新凸凹视频免费| 在线毛片片免费观看| 亚洲AV无码无限在线观看不卡| 亚洲国产精品一区二区九九|