實戰分析Tomcat的類載入器結構(使用Eclipse MAT驗證)
一、前言
在各種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 原始碼編譯、除錯的文章,根本沒幾個人看呢。。。畢生絕學都拿出來了,哭。。