欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Tomcat源碼分析

系統(tǒng) 1916 0

?前言:

  本文是我閱讀了TOMCAT源碼后的一些心得。 主要是講解TOMCAT的系統(tǒng)框架, 以及啟動(dòng)流程。若有錯(cuò)漏之處,敬請批評(píng)指教!

建議:

  畢竟TOMCAT的框架還是比較復(fù)雜的, 單是從文字上理解, 是不那么容易掌握TOMCAT的框架的。 所以得實(shí)踐、實(shí)踐、再實(shí)踐。 建議下載一份TOMCAT的源碼, 調(diào)試通過, 然后單步跟蹤其啟動(dòng)過程。 如果有不明白的地方, 再來查閱本文, 看是否能得到幫助。 我相信這樣效果以及學(xué)習(xí)速度都會(huì)好很多!

  • 1. Tomcat的整體框架結(jié)構(gòu)

  Tomcat的基本框架, 分為4個(gè)層次。
  Server和Service
  Connector
    HTTP
    AJP
  Container
    Engine
    Host
    Context
  Component
    manager
    logger
    loader
    pipeline
    valve
    ...
站在框架的頂層的是Server和Service

  Server: 其實(shí)就是BackGroud程序, 在Tomcat里面的Server的用處是啟動(dòng)和監(jiān)聽服務(wù)端事件(諸如重啟、關(guān)閉等命令。 在tomcat的標(biāo)準(zhǔn)配置文件:server.xml里面, 我們可以看到“<Server port="8005" shutdown="SHUTDOWN" debug="0">;”這里的"SHUTDOWN"就是server在監(jiān)聽服務(wù)端事件的時(shí)候所使用的命令字)
  Service: 在tomcat里面,service是指一類問題的解決方案。 通常我們會(huì)默認(rèn)使用tomcat提供的:Tomcat-Standalone 模式的service。 在這種方式下的service既給我們提供解析jsp和servlet的服務(wù), 同時(shí)也提供給我們解析靜態(tài)文本的服務(wù)。

Connector

  Tomcat都是在容器里面處理問題的, 而容器又到哪里去取得輸入信息呢?
  Connector就是專干這個(gè)的。 他會(huì)把從socket傳遞過來的數(shù)據(jù), 封裝成Request, 傳遞給容器來處理。
  通常我們會(huì)用到兩種Connector,一種叫http connectoer, 用來傳遞http需求的。 另一種叫AJP, 在我們整合apache與tomcat工作的時(shí)候,apache與tomcat之間就是通過這個(gè)協(xié)議來互動(dòng)的。 (說到apache與tomcat的整合工作, 通常我們的目的是為了讓apache 獲取靜態(tài)資源, 而讓tomcat來解析動(dòng)態(tài)的jsp或者servlet。)


Container

  當(dāng)http connector把需求傳遞給頂級(jí)的container---Engin的時(shí)候, 我們的視線就應(yīng)該移動(dòng)到Container這個(gè)層面來了。
  在Container這個(gè)層, 我們包含了3種容器:Engin, Host, Context.
  Engin :收到service傳遞過來的需求, 處理后, 將結(jié)果返回給service( service 是通過connector 這個(gè)媒介來和Engin互動(dòng)的).
  Host : Engin收到service傳遞過來的需求后,不會(huì)自己處理, 而是交給合適的Host來處理。Host在這里就是虛擬主機(jī)的意思, 通常我們都只會(huì)使用一個(gè)主機(jī),既“l(fā)ocalhost”本地機(jī)來處理。
  Context : Host接到了從Host傳過來的需求后, 也不會(huì)自己處理, 而是交給合適的Context來處理。
  比如:<http://127.0.0.1:8080/foo/index.jsp>;
     <http://127.0.1:8080/bar/index.jsp>;
  前者交給foo這個(gè)Context來處理, 后者交給bar這個(gè)Context來處理。很明顯吧!context的意思其實(shí)就是一個(gè)web app的意思。
  我們通常都會(huì)在server.xml里面做這樣的配置<Context path="/foo" docBase="D:/project/foo/web" />;這個(gè)context容器,就是用來干我們該干的事兒的地方的。

Compenent : 接下來, 我們繼續(xù)講講component是干什么用的。
  我們得先理解一下容器和組件的關(guān)系。
  需求被傳遞到了容器里面, 在合適的時(shí)候, 會(huì)傳遞給下一個(gè)容器處理。而容器里面又盛裝著各種各樣的組件, 我們可以理解為提供各種各樣的增值服務(wù)。
  manager : 當(dāng)一個(gè)容器里面裝了manager組件后,這個(gè)容器就支持session管理了, 事實(shí)上在tomcat里面的session管理, 就是靠的在context里面裝的manager component.
  logger : 當(dāng)一個(gè)容器里面裝了logger組件后, 這個(gè)容器里所發(fā)生的事情, 就被該組件記錄下來啦! 我們通常會(huì)在logs/ 這個(gè)目錄下看見catalina_log.time.txt 以及    localhost.time.txt 和localhost_examples_log.time.txt。 這就是因?yàn)槲覀兎謩e為:engin, host以及context(examples)這三個(gè)容器安裝了logger組件, 這也是默認(rèn)安裝, 又叫做標(biāo)配 :)
  loader : loader這個(gè)組件通常只會(huì)給我們的context容器使用,loader是用來啟動(dòng)context以及管理這個(gè)context的classloader用的。
  pipline : pipeline是這樣一個(gè)東西, 當(dāng)一個(gè)容器決定了要把從上級(jí)傳遞過來的需求交給子容器的時(shí)候, 他就把這個(gè)需求放進(jìn)容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流動(dòng)的時(shí)候, 就會(huì)被管道里面的各個(gè)閥門攔截下來。 比如管道里面放了兩個(gè)閥門。 第一個(gè)閥門叫做“access_allow_vavle”, 也就是說需求流過來的時(shí)候,它會(huì)看這個(gè)需求是哪個(gè)IP過來的, 如果這個(gè)IP已經(jīng)在黑名單里面了,sure, 殺! 第二個(gè)閥門叫做“defaul_access_valve”它會(huì)做例行的檢查, 如果通過的話,OK, 把需求傳遞給當(dāng)前容器的子容器。 就是通過這種方式, 需求就在各個(gè)容器里面?zhèn)鬟f,流動(dòng), 最后抵達(dá)目的地的了。
  valve : 就是上面所說的閥門啦。
  Tomcat里面大概就是這么些東西, 我們可以簡單地這么理解tomcat的框架,它是一種自上而下, 容器里又包含子容器的這樣一種結(jié)構(gòu)。

  • 2. Tomcat的啟動(dòng)流程

這篇文章是講tomcat怎么啟動(dòng)的,既然我們大體上了解了TOMCAT的框架結(jié)構(gòu)了, 那么我們可以望文生意地就猜到tomcat的啟動(dòng), 會(huì)先啟動(dòng)父容器,然后逐個(gè)啟動(dòng)里面的子容器。 啟動(dòng)每一個(gè)容器的時(shí)候, 都會(huì)啟動(dòng)安插在他身上的組件。 當(dāng)所有的組件啟動(dòng)完畢, 所有的容器啟動(dòng)完畢的時(shí)候,tomcat本身也就啟動(dòng)完畢了。
順理成章地, 我們同樣可以猜到,tomcat的啟動(dòng)會(huì)分成兩大部分, 第一步是裝配工作。 第二步是啟動(dòng)工作。
  裝配工作 就是為父容器裝上子容器, 為各個(gè)容器安插進(jìn)組件的工作。 這個(gè)地方我們會(huì)用到digester模式, 至于digester模式什么, 有什么用, 怎么工作的. 請參考<http://software.ccidnet.com/pub/article/c322_a31671_p2.html>;
  啟動(dòng)工作 是在裝配工作之后, 一旦裝配成功了, 我們就只需要點(diǎn)燃最上面的一根導(dǎo)線, 整個(gè)tomcat就會(huì)被激活起來。 這就好比我們要開一輛已經(jīng)裝配好了的汽車的時(shí)候一樣,我們只要把鑰匙插進(jìn)鑰匙孔,一擰,汽車的引擎就會(huì)發(fā)動(dòng)起來,空調(diào)就會(huì)開起來, 安全裝置就會(huì)生效, 如此一來,汽車整個(gè)就發(fā)動(dòng)起來了。(這個(gè)過程確實(shí)和TOMCAT的啟動(dòng)過程不謀而和, 讓我們不得不懷疑TOMCAT的設(shè)計(jì)者是在GE做JAVA開發(fā)的)。

  • 2.1 一些有意思的名稱:

  Catalina
  Tomcat
  Bootstrap
  Engin
  Host
  Context
他們的意思很有意思:
  Catalina: 遠(yuǎn)程轟炸機(jī)
  Tomcat: 熊貓轟炸機(jī)-- 轟炸機(jī)的一種(這讓我想起了讓國人引以為豪的熊貓手機(jī),是不是英文可以叫做tomcat??? , 又讓我想起了另一則廣告: 波導(dǎo)-手機(jī)中的戰(zhàn)斗機(jī)、波音-客機(jī)中的戰(zhàn)斗機(jī) )
  Bootstap: 引導(dǎo)
  Engin: 發(fā)動(dòng)機(jī)
  Host: 主機(jī),領(lǐng)土
  Context: 內(nèi)容, 目標(biāo), 上下文

  ... 在許多許多年后, 現(xiàn)代人類已經(jīng)滅絕。 后現(xiàn)代生物發(fā)現(xiàn)了這些單詞零落零落在一塊。 一個(gè)自以為聰明的家伙把這些東西翻譯出來了:
在地勤人員的引導(dǎo)(bootstrap)下, 一架轟炸架(catalina)騰空躍起, 遠(yuǎn)看是熊貓轟炸機(jī)(tomcat), 近看還是熊貓轟炸機(jī)! 憑借著優(yōu)秀的發(fā)動(dòng)機(jī)技術(shù)(engin), 這架熊貓轟炸機(jī)飛臨了敵國的領(lǐng)土上空(host), 對(duì)準(zhǔn)目標(biāo)(context)投下了毀天滅地的核彈頭,波~ 現(xiàn)代生物就這么隔屁了~

  綜上所述, 這又不得不讓人聯(lián)想到GE是不是也參與了軍事設(shè)備的生產(chǎn)呢?
  反對(duì)美帝國主義! 反對(duì)美霸權(quán)主義! 和平萬歲! 自由萬歲!

  • 2.2 歷史就是那么驚人的相似

  tomcat的啟動(dòng)就是從org.apache.catalina.startup.Bootstrap這個(gè)類悍然啟動(dòng)的!

  在Bootstrap里做了兩件事:
    1. 指定了3種類型classloader:
      commonLoader: common/classes、common/lib、common/endorsed
      catalinaLoader: server/classes、server/lib、commonLoader
      sharedLoader: shared/classes、shared/lib、commonLoader
    2. 引導(dǎo)Catalina的啟動(dòng)。
      用Reflection技術(shù)調(diào)用org.apache.catalina.startup.Catalina的process方法, 并傳遞參數(shù)過去。

  • 2.3 Catalina.java

  Catalina完成了幾個(gè)重要的任務(wù):
    1. 使用Digester技術(shù)裝配tomcat各個(gè)容器與組件。
      1.1 裝配工作的主要內(nèi)容是安裝各個(gè)大件。 比如server下有什么樣的servcie。Host會(huì)容納多少個(gè)context。Context都會(huì)使用到哪些組件等等。
      1.2 同時(shí)呢, 在裝配工作這一步, 還完成了mbeans的配置工作。 在這里,我簡單地但不十分精確地描述一下mbean是什么,干什么用的。
        我們自己生成的對(duì)象, 自己管理, 天經(jīng)地義! 但是如果我們創(chuàng)建了對(duì)象了, 想讓別人來管, 怎么辦呢? 我想至少得告訴別人我們都有什么, 以及通過什么方法可以找到 吧!JMX技術(shù)給我們提供了一種手段。JMX里面主要有3種東西。Mbean, agent, connector.
        Mbean: 用來映射我們的對(duì)象。也許mbean就是我們創(chuàng)建的對(duì)象, 也許不是, 但有了它, 就可以引用到我們的對(duì)象了。
        Agent: 通過它, 就可以找到mbean了。
        Connector: 連接Agent的方式。 可以是http的, 也可以是rmi的,還可以直接通過socket。
              發(fā)生在tomcat 裝配過程中的事情: GlobalResourcesLifecycleListener 類的初始化會(huì)被觸發(fā):
              protected static Registry registry = MBeanUtils.createRegistry(); 會(huì)運(yùn)行
              MBeanUtils.createRegistry() 會(huì)依據(jù)/org/apache/catalina/mbeans/mbeans- descriptors.xml這個(gè)配置文件創(chuàng)建mbeans. Ok, 外界就有了條途徑訪問tomcat中的各個(gè)組件了。(有點(diǎn)像后門兒)
    2. 為top level 的server 做初始化工作。 實(shí)際上就是做通常會(huì)配置給service的兩條connector.(http, ajp)
    3. 從server這個(gè)容器開始啟動(dòng), 點(diǎn)燃整個(gè)tomcat.
    4. 為server做一個(gè)hook程序, 檢測當(dāng)server shutdown的時(shí)候, 關(guān)閉tomcat的各個(gè)容器用。
    5. 監(jiān)聽8005端口, 如果發(fā)送"SHUTDOWN"(默認(rèn)培植下字符串)過來, 關(guān)閉8005serverSocket。

  • 2.4 啟動(dòng)各個(gè)容器

   1. Server
    觸發(fā)Server容器啟動(dòng)前(before_start), 啟動(dòng)中(start), 啟動(dòng)后(after_start)3個(gè)事件, 并運(yùn)行相應(yīng)的事件處理器。
    啟動(dòng)Server的子容器:Servcie.
   2. Service
    啟動(dòng)Service的子容器:Engin
    啟動(dòng)Connector
   3. Engin
    到了Engin這個(gè)層次,以及以下級(jí)別的容器,Tomcat就使用了比較一致的啟動(dòng)方式了。
    首先, 運(yùn)行各個(gè)容器自己特有一些任務(wù)
    隨后, 觸發(fā)啟動(dòng)前事件
    立即, 設(shè)置標(biāo)簽,就表示該容器已經(jīng)啟動(dòng)
    接著, 啟動(dòng)容器中的各個(gè)組件:loader, logger, manager等等
    再接著,啟動(dòng)mapping組件。(注1)
    緊跟著,啟動(dòng)子容器。
    接下來,啟動(dòng)該容器的管道(pipline)
    然后, 觸發(fā)啟動(dòng)中事件
    最后, 觸發(fā)啟動(dòng)后事件。

    Engin大致會(huì)這么做,Host大致也會(huì)這么做, Context大致還是會(huì)這么做。 那么很顯然地, 我們需要在這里使用到代碼復(fù)用的技術(shù)。tomcat在處理這個(gè)問題的時(shí)候, 漂亮地使用了抽象類來處理。ContainerBase. 最后使得這部分完成復(fù)雜功能的代碼顯得干凈利落, 干練爽快, 實(shí)在是令人覺得嘆為觀止, 細(xì)細(xì)品來, 直覺如享佳珍, 另人齒頰留香, 留戀往返啊!

    Engin的觸發(fā)啟動(dòng)前事件里, 會(huì)激活綁定在Engin上的唯一一個(gè)Listener:EnginConfig。
這個(gè)EnginConfig類基本上沒有做什么事情, 就是把EnginConfig的調(diào)試級(jí)別設(shè)置為和Engin相當(dāng)。 另外就是輸出幾行文本, 表示Engin已經(jīng)配置完畢, 并沒有做什么實(shí)質(zhì)性的工作。
    注1: mapping組件的用處是, 當(dāng)一個(gè)需求將要從父容器傳遞到子容器的時(shí)候, 而父容器又有多個(gè)子容器的話, 那么應(yīng)該選擇哪個(gè)子容器來處理需求呢? 這個(gè)由mapping 組件來定奪。

   4. Host
    同Engin一樣, 也是調(diào)用ContainerBase里面的start()方法, 不過之前做了些自個(gè)兒的任務(wù),就是往Host這個(gè)容器的通道(pipline)里面, 安裝了一個(gè)叫做
“org.apache.catalina.valves.ErrorReportValve”的閥門。
這個(gè)閥門的用處是這樣的: 需求在被Engin傳遞給Host后, 會(huì)繼續(xù)傳遞給Context做具體的處理。 這里需求其實(shí)就是作為參數(shù)傳遞的Request, Response。 所以在context把需求處理完后, 通常會(huì)改動(dòng)response。 而這個(gè)org.apache.catalina.valves.ErrorReportValve的作用就是檢察response是否包含錯(cuò)誤, 如果有就做相應(yīng)的處理。
   5. Context
    到了這里, 就終于輪到了tomcat啟動(dòng)中真正的重頭戲,啟動(dòng)Context了。
    StandardContext.start() 這個(gè)啟動(dòng)Context容器的方法被StandardHost調(diào)用.
    5.1 webappResources 該context所指向的具體目錄
    5.2 安裝defaultContex, DefaultContext 就是默認(rèn)Context。 如果我們在一個(gè)Host下面安裝了DefaultContext,而且defaultContext里面又安裝了一個(gè)數(shù)據(jù)庫連接池資源的話。 那么其他所有的在該Host下的Context, 都可以直接使用這個(gè)數(shù)據(jù)庫連接池, 而不用格外做配置了。
    5.3 指定Loader. 通常用默認(rèn)的org.apache.catalina.loader.WebappLoader這個(gè)類。 Loader就是用來指定這個(gè)context會(huì)用到哪些類啊, 哪些jar包啊這些什么的。
    5.4 指定Manager. 通常使用默認(rèn)的org.apache.catalina.session. StandardManager 。Manager是用來管理session的。
      其實(shí)session的管理也很好實(shí)現(xiàn)。 以一種簡單的session管理為例。 當(dāng)需求傳遞過來的時(shí)候, 在Request對(duì)象里面有一個(gè)sessionId 屬性。OK, 得到這個(gè)sessionId后, 我們就可以把它作為map的key,而value我們可以放置一個(gè)HashMap. HashMap里邊兒, 再放我們想放的東西。
    5.5 postWorkDirectory (). Tomcat下面有一個(gè)work目錄。 我們把臨時(shí)文件都扔在那兒去。 這個(gè)步驟就是在那里創(chuàng)建一個(gè)目錄。 一般說來會(huì)在%CATALINA_HOME%/work/Standalone\localhost\ 這個(gè)地方生成一個(gè)目錄。
    5.6 Binding thread。到了這里, 就應(yīng)該發(fā)生class Loader 互換了。 之前是看得見tomcat下面所有的class和lib. 接下來需要看得見當(dāng)前context下的class。 所以要設(shè)置contextClassLoader, 同時(shí)還要把舊的ClassLoader記錄下來,因?yàn)橐院筮€要用的。
    5.7 啟動(dòng)Loader. 指定這個(gè)Context具體要使用哪些classes, 用到哪些jar文件。 如果reloadable設(shè)置成了true, 就會(huì)啟動(dòng)一個(gè)線程來監(jiān)視classes的變化, 如果有變化就重新啟動(dòng)Context。
    5.8 啟動(dòng)logger
    5.9 觸發(fā)安裝在它身上的一個(gè)監(jiān)聽器。
      lifecycle.fireLifecycleEvent(START_EVENT, null);
      作為監(jiān)聽器之一,ContextConfig會(huì)被啟動(dòng). ContextConfig就是用來配置web.xml的。 比如這個(gè)Context有多少Servlet, 又有多少Filter, 就是在這里給Context裝上去的。
      5.9.1 defaultConfig. 每個(gè)context都得配置tomcat/conf/web.xml 這個(gè)文件。
      5.9.2 applicationConfig 配置自己的WEB-INF/web.xml 文件
      5.9.3 validateSecurityRoles 權(quán)限驗(yàn)證。 通常我們在訪問/admin 或者/manager的時(shí)候,需要用戶要么是admin的要么是manager的, 才能訪問。 而且我們還可以限制那些資源可以訪問, 而哪些不能。 都是在這里實(shí)現(xiàn)的。
      5.9.4 tldScan: 掃描一下, 需要用到哪些標(biāo)簽(tag lab)
    5.10 啟動(dòng)manager
    5.11 postWelcomeFiles() 我們通常會(huì)用到的3個(gè)啟動(dòng)文件的名稱:
        index.html、index.htm、index.jsp 就被默認(rèn)地綁在了這個(gè)context上
    5.12 listenerStart 配置listener
    5.13 filterStart 配置filter
    5.14 啟動(dòng)帶有<load-on-startup>;1</load-on-startup>;的Servlet.
       順序是從小到大:1,2,3… 最后是0
       默認(rèn)情況下, 至少會(huì)啟動(dòng)如下3個(gè)的Servlet:
       org.apache.catalina.servlets.DefaultServlet
            處理靜態(tài)資源的Servlet. 什么圖片啊,html啊,css啊,js啊都找他
       org.apache.catalina.servlets.InvokerServlet
            處理沒有做Servlet Mapping的那些Servlet.
       org.apache.jasper.servlet.JspServlet
            處理JSP文件的.
    5.15 標(biāo)識(shí)context已經(jīng)啟動(dòng)完畢。
  走了多少個(gè)步驟啊,Context總算是啟動(dòng)完畢嘍。
  OK! 走到了這里, 每個(gè)容器以及組件都啟動(dòng)完畢。Tomcat終于不辭辛勞地為人民服務(wù)了!

  • 3. 參考文獻(xiàn):

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

  • 4. tomcat源碼分析(消息處理)

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

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

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



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

   以http://localhost:8080/web/login.jsp為例子
    (以下例子, 都是以tomcat4 源碼為參考)

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

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

  中期:講解了被tomcat抓住后,又是怎么在各個(gè)容器里面穿梭, 最后到達(dá)最后的處理地點(diǎn)。

  末期:講解到達(dá)最后的處理地點(diǎn)后,又是怎么具體處理的。

  2、 前期Request的born.

    在這里我先簡單講一下request這個(gè)東西。

    我們先看著這個(gè)URL:http://localhost:8080/web/login.jsp 它是動(dòng)用了8080端口來進(jìn)行socket通訊的。

    我們知道, 通過

    InputStream in = socket.getInputStream() 和OutputStream out = socket.getOutputStream()

    就可以實(shí)現(xiàn)消息的來來往往了。

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

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

    我們可以簡單地把Request看成管發(fā)到服務(wù)器來的數(shù)據(jù),把Response看成想發(fā)出服務(wù)器的數(shù)據(jù)。


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

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



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

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

    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. 啟動(dòng)線程池.

    3. 調(diào)出線程池里面空閑的工作線程。

    4. 把8080端口傳過來由httpd協(xié)議封裝的數(shù)據(jù),解析成Request和Response對(duì)象。

    5. 使用Http11Processor來處理request

    6. 在Http11Processor里面, 又會(huì)call CoyoteAdapter來進(jìn)行適配處理,把Request適配成實(shí)現(xiàn)了ServletRequest和HttpServletRequest接口的CoyoteRequest.

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



  3. 中期。 在各個(gè)容器間的穿梭。

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

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

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

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

    讓我們來想象一下:

    當(dāng)一個(gè)Request進(jìn)入一個(gè)容器后, 它就在管道里面流動(dòng),波羅~ 波羅~ 波羅~ 地穿過各個(gè)閥門。在流到最后一個(gè)閥門的時(shí)候,吧唧~ 那個(gè)該死的閥門就把它扔給了子容器。 然后又開始 波羅~ 波羅~ 波羅~ ... 吧唧~.... 波羅~ 波羅~ 波羅~ ....吧唧~....

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

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



    3.1 StandardEngin 的pipeline里面放的是:StandardEnginValve

      在這里,VALVE做了三件事:

      1. 驗(yàn)證傳遞過來的request是不是httpservletRequest.

      2 驗(yàn)證傳遞過來的request 是否攜帶了host header信息.

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

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



    3.2 StandardHost 的pipline里面放的是:StandardHostValve

      1. 驗(yàn)證傳遞過來的request是不是httpservletRequest.

      2. 根據(jù)Request來確定哪個(gè)Context來處理。

        Context其實(shí)就是webapp, 比如http://localhost:8080/web/login.jsp

        這里web就是Context羅!

      3. 既然確定了是哪個(gè)Context了,那么就應(yīng)該把那個(gè)Context的classloader付給當(dāng)前線程了。

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

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

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

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

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



    3.3 StandardContext 的pipline里面放的是:StandardContextValve

      1. 驗(yàn)證傳遞過來的request是不是httpservletRequest.

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

      3. 這個(gè)時(shí)候就會(huì)根據(jù)Request到底是Servlet,還是jsp,還是靜態(tài)資源來決定到底用哪種Wrapper來處理這個(gè)Reqeust了。

      4. 一旦決定了到底用哪種Wrapper,OK,交給那個(gè)Wrapper處理。



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

    StandardWrapper

    之前對(duì)Wrapper沒有做過講解,其實(shí)它是這樣一種東西。

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

    處理靜態(tài)的:org.apache.catalina.servlets.DefaultServlet

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

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

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

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

    具體情況是這么滴:

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

      如果request是找 靜態(tài)資源 ,StandardWrapper里面就會(huì)封裝一個(gè)org.apache.jasper.servlet.DefaultServlet 去處理它。

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



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

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

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

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

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

      如果是DefaultServlet, 就直接找到靜態(tài)資源,取出內(nèi)容, 發(fā)送出去。

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

    ok! 完畢。

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

參考:

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

Tomcat源碼分析


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 午夜影院黄色 | 偷拍做爰吃奶视频免费看 | 日韩精品视频在线观看免费 | 国产二区视频 | 欧美日韩中文字幕 | 12av毛片| 日韩一区二区不卡 | 777xacom| 成人 日韩 在线 | 亚洲影视在线 | 一二三区av | 草草国产成人免费视频 | 97色免费视频 | 免费视频片在线观看大片 | 一级片亚洲 | 国产香港一级毛片在线看 | 激情 婷婷 | 很黄很色的小视频在线网站 | 色天天天天综合男人的天堂 | 国产成人一区二区三区电影 | 亚洲高清专区 | 久久a区 | 亚洲熟妇毛茸茸 | 久久精品91久久久久久再现 | 久久久精 | 久久亚洲二区 | 日本美女一区二区 | 亚洲高清中文字幕综合网 | 欧美午夜一区 | 国产美女一区二区三区 | 91精品欧美久久久久久动漫 | 男女生性毛片免费观看 | 黄色影片在线免费观看 | 久久亚洲精品国产精品黑人 | 大香伊人久久精品一区二区 | 国产日韩中文字幕 | 五月色开心婷婷丁香在线 | 成人精品鲁一区一区二区 | 色婷婷综合在线 | 国产精品夜色一区二区三区 | 亚洲有码转帖 |