實戰分析Tomcat的類載入器結構(使用Eclipse MAT驗證)

三國夢迴發表於2019-06-09

一、前言

在各種Tomcat相關書籍,書上都提到了其類載入器結構:

 

在Tomcat 7或者8中,共享類和Catalina類載入器在catalina.properties中都是沒配置的,請看:

 

所以,catalina和shared是直接把common的類載入器賦值給了它們,這三者其實都是同一個類載入器。

 

這次我們來驗證下,方法是通過jmap匯出記憶體堆疊,然後用eclipse 的MAT工具進行分析。

 

二、步驟

 1、獲取記憶體dump

我的tomcat是7.0.68,webapps只有預設的幾個應用。

在命令列執行下面語句,獲取pid:

 ps -ef|grep java

 

然後執行:

jmap -dump:live,format=b,file=heap.bin  此處為pid佔位符

 

2、eclipse MAT查詢org.apache.catalina.loader.WebappClassLoader

用MAT開啟heap.bin後,會讓你選擇分析的型別,我們選擇Component Report即可。

接下來,正式開始分析:

我們知道,tomcat中的應用載入器,類名即為org.apache.catalina.loader.WebappClassLoader。

我們這裡,直接用oql語言(eclipse mat中語法)來查詢該類的物件:

 

 

可以看到,共有5個物件。

 

5個物件,分別對應了預設的5個應用,manager、host manaer、docs、root、example。

我們選擇第一個,檢視下圖,可知,該classload是為manager應用服務的,其他幾個就不一一截圖了:

 

 

從上圖也可以簡單看出來,類載入路徑就是簡單地去自己context目錄下的 WEB-INF/lib 、WEB-INF/classes下查詢。

(當然,具體的實現沒這麼簡單,會根據類名稱以及delegate 引數,選擇是給j2seClassLoader載入(載入jre/lib/ext下的),還是給parent

來載入,還是自己載入。) 

 

3、檢視WebappClassLoader 的parent 載入器

按照理論上說,WebappClassLoader的parent,即為common類載入器,主要載入tomcat自己的類,即catalina.base中lib下面的類。

 

我們上圖看看:

 

 從圖上可以看出來,確實沒騙我,載入的類路徑確實就是tomcat的lib目錄。

 

我們順便,驗證下,common、server、share都執行同一個引用。下圖可以看出來,確實沒錯。

 

 

 4、檢視common類載入器的parent

我們繼續往上追溯,common的parent,應該是jdk的預設類載入器,型別為sun.misc.Launcher$AppClassLoader,主要負責載入classpath下的東西。

這裡,看看我們的classpath是哪個:

 

 

 上圖可以看出來,classpath下,只有2個類(忽略greys-agent.jar,那個是除錯工具),即bootstrap.jar 和tomcat-juli.jar(Tomcat內部日誌)。

 

到這裡,我們的驗證基本就結束了。

 

三、總結

這裡,從第四點,我有一些感想,似乎明白了:

為什麼tomcat的啟動原始碼裡,即bootstrap類中,一上來就要設定執行緒上下文類載入器。

 

 

原因就是,BootStrap是應用類載入器載入的,只載入了Bootstrap和tomcat-juli.jar。而tomcat/lib下沒法載入。

所以就馬上新建了commonLoader,(和catalinLoader、sharedLoader同一個引用),而且設定為執行緒類載入器,方便進行後續的類載入。

 

說實話,但我覺得,tomcat的bootstrp.jar和tomcat-juli.jar為啥不直接放到lib目錄下,大家都直接使用common類載入器算了,搞不懂搞不懂。

今天分享就到這。

 

ps:題外話,為啥上一篇寫的openjdk 原始碼編譯、除錯的文章,根本沒幾個人看呢。。。畢生絕學都拿出來了,哭。。

相關文章