tomcat學習步驟,附帶打破雙親委派模型企業應用實戰

1. tomcat入門

入門模塊僅作學習大綱梳理,忽略了具體操做指引。html

Tomcat的三種部署模式:

簡單架構模型

 

鏈接器的非阻塞模式(NIO)

                                                                                                                                              通道(Channel)、緩衝區(Buffer)、選擇器(Selector)mysql

 

容器container的責任鏈模式:

1.請求被Connector組件接收,建立Request和Response對象。web

2.Connector將Request和Response交給Container,先經過Engine的pipeline組件流經內部的每一個Valve。spring

3.請求流轉到Host的pipeline組件中,而且通過內部Valve的過。sql

4.請求流轉到Context的pipeline組件中,而且通過內部的Valve的過濾。數據庫

5.請求流轉到Wrapper的pipeline組件中,而且通過內部的Valve的過濾。tomcat

6.Wrapper內部的WrapperValve建立FilterChain實例,調用指定的Servlet實例處理請求。安全

7.返回。服務器

 

 

2.tomcat架構進階

 

 

tomcat頂層結構

 

 

 

 

Server:服務器的意思,表明整個tomcat服務器,一個tomcat只有一個Server;網絡

Service:Server中的一個邏輯功能層, 一個Server能夠包含多個Service;

Connector:稱做鏈接器,是Service的核心組件之一,一個Service能夠有多個Connector,主要是鏈接客戶端請求;

Container:Service的另外一個核心組件,按照層級有Engine,Host,Context,Wrapper四種,一個Service只有一個Engine,其主要做用是執

行業務邏輯;
Jasper:JSP引擎;
Session:會話管理;

 

Connector解析

 

 

 

Connector使用ProtocolHandler來處理請求的Endpoint用來處理底層Socket的網絡鏈接。

Processor用於將Endpoint接收到的Socket封裝成Request。

Adapter充當適配器,用於將Request轉換爲ServletRequest交給Container進行具體的處理。

ProtocolHandler由包含了三個部件:Endpoint、Processor,Adapter

Container解析

 

 

service中的name是catalina,engine中的name也是catalina,這個就證實一個service就只有一個engine, 一個engine能夠有多個host主機

host,站點,虛擬主機。

Engine:引擎、只有一個定義了一個名爲Catalina的Engine

Host:站點、虛擬主機一個Engine包含多個Host的設計,使得一個服務器實例能夠承擔多個域名的服務,是很靈活的設計

Context:一個應用默認配置下webapps下的每一個目錄都是一個應用

Wrapper:一個Servlet

 

結合tomcat目錄結構理解上面的4個容器之間的關係

3.tomcat類加載機制

引用自:https://www.cnblogs.com/ghoster/p/7602158.html

 

1.主流的Java Web服務器,如Tomcat、Jetty、WebLogic、WebSphere等都實現了本身定義的類加載器(通常都不止一個)。由於一個功能健全的web服務器要解決一下幾個問題:

    1)部署在一個服務器上的兩個web應用程序所使用的Java類庫能夠實現互相隔離。這是最基本的需求,兩個不一樣的應用程序可能會依賴同一個第三方類庫的不一樣版本,不能要求一個類庫在一個服務器中只有一份,服務器應當保證兩個應用程序的類庫能夠互相獨立使用

    2)部署在同一個服務器上的兩個Web應用程序所使用的Java類庫能夠互相共享。這個需求也很是很常見,如,用戶可能有10各使用Spring組織的應用程序部署在同一臺服務器上,若是把10份Spring分別存放在各個應用程序的隔離目錄中,將會是很大的資源浪費-這主要不是浪費磁盤空間的問題,而是指類庫在使用時都要被加載到服務器內存,若是類庫不能共享,虛擬機的方法區就會很容易出現過分膨脹的風險

    3)服務器須要儘量地保證自身的安全不受部署的Web應用程序影響。目前,有許多主流的Java Web服務器自身也是使用Java語言來實現的。所以,服務器自己也有類庫依賴的問題,通常來講,基於安全考慮,服務器所使用的類庫應該與應用程序的類庫相互獨立

    4)支持jsp應用的Web服務器,大多數都須要支持HotSwap功能。咱們知道,jsp文件最終要編譯成Java Class才能由虛擬機執行,但jsp文件因爲其純文本存儲的特性,運行時修改的機率遠遠大於第三方類庫或程序自身的Class文件。並且ASP、PHP和JSP這些網頁應用也把修改後無需重啓做爲一個很大的「優點」來看待,所以,「主流」的Web服務器都會支持JSP的熱替換,固然也有「非主流」的,如運行在生產模式下的WebLogic服務器默認就不會處理JSP文件的變化

  因爲存在上述問題,在部署Web應用時,單獨的一個ClassPath就沒法知足需求了,因此各類Web服務器都「不約而同」地提供了好幾個ClassPath路徑供用戶存放第三方類庫,這些路徑通常都以lib或classes命名,被放置到不一樣路徑中的類庫,具有不一樣的訪問範圍和服務對象,一般,每個目錄都會有一個相應的自定義類加載器去加載放置在裏面的Java類庫。

  2.Tomcat對用戶類庫與類加載器的規劃

    在其目錄結構下有三組目錄(「/common/*」、「/server/*」、「/shared/*」)能夠存放Java類庫,另外還能夠加上Web應用程序自己的目錄「/WEB-INF/*」,一共4組,把Java類庫放置在這些目錄中的含義分別以下:

    1)放置在/commom目錄中:類庫可被Tomcat和全部的Web應用程序共同使用

    2)放置在/server目錄中:類庫可被Tomcat使用,對全部的Web應用程序都不可見

    3)放置在/shared目錄中:類庫可被全部的Web應用程序所共同使用,但對Tomcat本身不可見

    4)放置在/WebApp/WEB-INF目錄中:類庫僅僅能夠被此Web應用程序使用,對Tomcat和其餘Web應用程序都不可見

    爲了支持這套目錄結構,並對目錄裏面的類庫進行加載和隔離,Tomcat自定義了多個類加載器,這些類加載器按照經典的雙親委派模型來實現,所下圖:

    

    最上面的三個類加載器是JDK默認提供的類加載器,這三個加載器的的做用以前也說過,這裏再也不贅述了,能夠在http://www.cnblogs.com/ghoster/p/7594224.html簡單瞭解。而CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebAppClassLoader則是Tomcat本身定義的類加載器,他們分別加載/common/*、/server/*、/shared/*和/WebApp/WEB-INF/*中的Java類庫。其中WebApp類加載器和jsp類加載器一般會存在多個實例,每個Web應用程序對應一個WebApp類加載器,每個jsp文件對應一個Jsp類加載器

    從上圖的委派關係能夠看出,CommonClassLoader能加載的類均可以被CatalinaClassLoader和SharedClassLoader使用,而CatalinaClassLoader和SharedClassLoader本身能加載的類則與對方相互隔離。WebAppClassLoader可使用SharedClassLoader加載到的類,但各個WebAppClassLoader實例之間相互隔離。而JasperLoader的加載範圍僅僅是這個JSP文件所編譯出來的哪個Class,它出現的目的就是爲了被丟棄:當服務器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例,並經過在創建一個新的Jsp類加載器來實現JSP文件的HotSwap功能

 

4.打破雙親委派模型企業級應用實戰

需求背景:在使用多數據源的狀況下,同時鏈接某大廠魔改的數據庫mppdb和pgsql數據庫的時候。出現了沒法同時加載mppdb和pgsql的驅動的問題。

 

緣由分析:spring在啓動時會調用應用類加載器加載org目錄下的.class文件,同時spring自定義類加載器分別加載BOOT-INF,META-INF 目錄下的文件,mppdb 與pgsql驅動的本質都是.jar文件,因此會放在META-INF目錄下的lib目錄下。

又由於mppdb是某國內大廠以pgsql爲藍本魔改的,遺留下一個問題,mppdb與mysql驅動的類名是徹底一致的。而兩驅動都放在lib目錄下,由同一個類加載器來加載,就會出現如下狀況:當第一個驅動pgsql加載時,使用雙親機制正常加載,

當第二個驅動mppdb再次加載時,會判斷該類是否加載過,此時,因爲類加載器一致,類名一致,類加載器會誤認爲mppdb驅動已經加載過了,實際是以前加載的pgsql驅動,因此spring不會再去加載mppdb,而是從緩衝中把pgsql的驅動拋出,

從而致使了,spring在啓動時沒法同時加載mppdn驅動和pgsql驅動。

 

解決方案:

方案一:遵循雙親委派模型

在spring容器啓動後(此時spring已經加載到其中一個驅動,假設是pgsql驅動),新開一個jvm進程,在該進程中使用擴展類加載器加載mppdb驅動,根據雙親委派模型,擴展類加載器是應用類加載器的父類,當須要加載驅動時會優先委派父類加載,

因此同一個類在父類加載器和子類加載器都能加載的狀況下,父類加載器總能優先加載的。這樣就保證了,新起的進程老是能加載到擴展類加載器加載的mppdb驅動。

方案二:打破雙親委派模型

在spring容器啓動後(此時spring已經加載到其中一個驅動,假設是pgsql驅動),沒必要新開進程,仍是在該spring的進程內,使用應用類加載器XMLClassLoader去加載mppdb驅動,若是此時使用雙親委派模型,會加載到spring初始化時加載到的驅動,即pgsql驅動,

故而 須要將XMLClassLoader 的父加載器設置爲null,禁止其父加載器加載,而由其本身加載,便可以成功加載mppdb驅動,具體實現涉及公司信息安全,在此僅提供問題解決思路。

相關文章
相關標籤/搜索