Tomcat源碼分析(零) : 整體架構(gòu)

Tomcat 9.0 源碼

Tomcat架構(gòu)及其重要組件

Tomcat的系統(tǒng)架構(gòu)
Tomcat的系統(tǒng)架構(gòu)
  • Server是管理Service接口的,是Tomcat的一個頂級容器要尔。管理著多個Service
  • Service 是服務(wù),管理這一個Container和多個Connector低矮,Service的存在依賴于Server
  • Container : 一個或者多個Container 可以對應(yīng)一個Connector,這樣就組成了一個Service遵馆,Service生命周期的由Server進行管理妒蔚。
  • Container和Connector之間的交互媒介是Service,一個Service可以對應(yīng)多個Connector邪驮,但是只能有一個Container容器

Server

  • Server 管理著所有的Service锯玛。它的主要作用是提供一個接口可以讓其它程序能夠訪問這個Service集合,同時維護所有service的生命周期等歼捐。

Server在Tomcat中的標準實現(xiàn)是StandardServer。看一下其內(nèi)部的addServiec方法

   @Override
    //FIXME: 它是怎樣調(diào)用起來Service 方法的哪铁孵?
    public void addService(Service service) {

        service.setServer(this);
        //同步
        synchronized (servicesLock) {
            
            Service results[] = new Service[services.length + 1];
            System.arraycopy(services, 0, results, 0, services.length);
            results[services.length] = service;
            services = results;

            if (getState().isAvailable()) {
                try {
                    service.start();
                } catch (LifecycleException e) {
                    // Ignore
                }
            }

            // Report this property change to interested listeners
            support.firePropertyChange("service", null, service);
        }

    }

可以看到,在添加Service到Server的時候房资,它是將原有數(shù)組的長度加一并將數(shù)組添加到最后蜕劝。然后啟動最新添加的Service

Service

Service 在Tomcat中的標準實現(xiàn)是StandardService,Service 可以說是一個標準的服務(wù),擁有獨立的端口號。
在Service 中可以含有多個Connector和唯一的一個Container.這樣的設(shè)計模式可以允許 例如SSL加密過的請求和沒有經(jīng)過SSL加密的請求在一個APP中同時存在

Service 中的setContainer()

   @Override
    public void setContainer(Engine engine) {
        Engine oldEngine = this.engine;
        if (oldEngine != null) {
            // 移除原有Container
            oldEngine.setService(null);
        }
        this.engine = engine;
        if (this.engine != null) {
            this.engine.setService(this);
        }
        if (getState().isAvailable()) {
            if (this.engine != null) {
                try {
                    //開啟Engin
                    this.engine.start();
                } catch (LifecycleException e) {
                    log.warn(sm.getString("standardService.engine.startFailed"), e);
                }
            }
            // Restart MapperListener to pick up new engine.
            try {
                mapperListener.stop();
            } catch (LifecycleException e) {
                log.warn(sm.getString("standardService.mapperListener.stopFailed"), e);
            }
            try {
                mapperListener.start();
            } catch (LifecycleException e) {
                log.warn(sm.getString("standardService.mapperListener.startFailed"), e);
            }
            if (oldEngine != null) {
                try {
                    oldEngine.stop();
                } catch (LifecycleException e) {
                    log.warn(sm.getString("standardService.engine.stopFailed"), e);
                }
            }
        }

        // Report this property change to interested listeners
        support.firePropertyChange("container", oldEngine, this.engine);
    }

Service 的setContainer方法設(shè)置Engine容器轰异,然后啟動這個容器岖沛,并將原有的容器的停止掉。Service 的setConnector幾乎是同樣的套路

Container

Container 由四個子容器組成:

  • Engine : 表示整個Catalina Servlet引擎搭独,是Container 只用最高層婴削,用來管理Host 或者Context的實現(xiàn)
  • 如果你想攔截每一個到Servlet的請求,可以通過
  • Host :表示一個Engine管理下的一個虛擬主機牙肝,比如你訪問的Localhost就是一個虛擬主機唉俗。作用是運行多個應(yīng)用
    其處理過程可以總結(jié)如下:
    1. 為特定的請求URL選擇一個Context容器
    2. 把Context容器綁定到線程中
    3. 判斷是否是一個異步請求
    4. 讓Context去處理這個請求
    5. Context執(zhí)行invoke方法嗤朴,進入管道中,由StandardContextValve(是ContextValve的標準實現(xiàn)類)處理
  • Context:Context 是用來管理Servlet的容器虫溜,Context就對應(yīng)一個應(yīng)用雹姊。所以我們部署應(yīng)用時需要創(chuàng)建一個Context容器,Context負責管理Wrapper.
  • Wrapper : 用來管理一個Servlet的生命周期

Connector

Connector 是Tomcat的連接器衡楞,主要任務(wù)是負責處理瀏覽器發(fā)送過來的請求容为,并創(chuàng)建一個Request和Response對象,用于和前端Client交換數(shù)據(jù)寺酪,然后產(chǎn)生一個線程坎背,并將Request對象和Response對象傳遞給線程,后面對這兩個線程的處理就是Container的事情了

  1. 實例化Connector寄雀,構(gòu)造一個Connector對象
  2. 調(diào)用Connector的initIntenal方法得滤,初始化Connetor
  3. 調(diào)用ProtocolHanlder的init方法,完成ProtocolHanlder的初始化盒犹。這個過程包括了創(chuàng)建線程池并創(chuàng)建一個線程處理瀏覽器請求
  4. 調(diào)用Connector的startIntenal方法懂更,啟動Connector
  5. 調(diào)用ProtocolHandler的start方法,啟動Protocolhanlder
  6. 調(diào)用MapperListener的start方法急膀,啟動監(jiān)聽器程序

不同于Container ,Connector是一個實現(xiàn)類.其相當于一個容器處理基于Http的請求
沮协。CoyoteAdapter,是connector和container的橋梁,經(jīng)過這一步,請求就從connector傳遞到container中里了卓嫂。Adapter

要注意的是:最先處理請求的Request是org.apache.coyote.Request類型慷暂,這是一個Tomcat中一個輕量級對象,完成基本的請求處理后很容易被JVM回收晨雳,那為什么不直接交給Connector.Request對象處理呢行瑞?由于后者是Servlet容器真正傳遞的對象其完成的職責比前者復(fù)雜,這里使用org.apache.coyote.Request主要減輕后者的任務(wù)負擔餐禁,出于性能考慮才這么設(shè)計血久。

從connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);這句代碼中可以知道下一步的處理需要交給Container容器了。

Context容器和Wrapper

  • Wrapper 接口是Context的抽象接口

  • Context的啟動:

  • Context的啟動過程就是加載整個類資源文件和打開子容器帮非,以及pipeline的過程氧吐。

  • StandardContextValve的invoke 方法會通過request得到相應(yīng)的ContextWrapper,在這個過程中如果沒有發(fā)生異常,服務(wù)端會向client 發(fā)送一個ack響應(yīng)

  • StandardContext的處理流程可以用下面的圖來簡化:

  • StandardContext的addServlet會添加一個Servlet類,并通過Servlet名字分配一個ServletWrppar,如果沒有則為其新建一個末盔。通過這個Wrappar來管理這個Servlet筑舅。。
  • Wrapper與Servlet息息相關(guān)庄岖,其中的loadServlet負責裝載Servlet.Wrapper是最底層
  • Standard類主要負責初始化一個Servlet實例豁翎,并調(diào)用該實例的init方法角骤,然后通知感興趣的事件監(jiān)聽程序隅忿。用了Wrapper的invoke方法心剥,這個方法完成什么呢?

附錄: 一個HTTP請求是怎樣通過Tomcat到你的應(yīng)用中的

Http請求在Container中的傳遞流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末背桐,一起剝皮案震驚了整個濱河市优烧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌链峭,老刑警劉巖畦娄,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異弊仪,居然都是意外死亡熙卡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門励饵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驳癌,“玉大人,你說我怎么就攤上這事役听⊥窍剩” “怎么了?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵典予,是天一觀的道長甜滨。 經(jīng)常有香客問我,道長瘤袖,這世上最難降的妖魔是什么衣摩? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮捂敌,結(jié)果婚禮上昭娩,老公的妹妹穿的比我還像新娘。我一直安慰自己黍匾,他們只是感情好栏渺,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著锐涯,像睡著了一般磕诊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纹腌,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天霎终,我揣著相機與錄音,去河邊找鬼升薯。 笑死莱褒,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的涎劈。 我是一名探鬼主播广凸,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼阅茶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谅海?” 一聲冷哼從身側(cè)響起脸哀,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扭吁,沒想到半個月后撞蜂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡侥袜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年蝌诡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枫吧。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡送漠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出由蘑,到底是詐尸還是另有隱情闽寡,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布尼酿,位于F島的核電站爷狈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏裳擎。R本人自食惡果不足惜涎永,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹿响。 院中可真熱鬧羡微,春花似錦、人聲如沸惶我。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绸贡。三九已至盯蝴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間听怕,已是汗流浹背捧挺。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尿瞭,地道東北人闽烙。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像声搁,于是被迫代替她去往敵國和親黑竞。 傳聞我的和親對象是個殘疾皇子捕发,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容