本文旨在介紹JVM的類加載機制;同時分析Tomcat不能採用默認的加載機制的緣由,並對其加載機制作了介紹。
一、JVM中的類加載機制
在Java2以後的版本中,類的加載採用的是一種稱爲雙親委派的代理模型:也就是說當前ClassLoader在加載類前,先委派給雙親去加載類;
在有雙親委派模式的狀況下,啓動類裝載器能夠搶在標準擴展類裝載器以前去裝載類,而標準擴展類裝載器能夠搶在系統類裝載器以前去裝載那個類,類路徑類裝載器又能夠搶在用戶自定義類裝載器以前去裝載它,用這種方法,類裝載器的體系結構就能夠防止不可靠的代碼用它們本身的版原本替代可信任的類。
Bootstrap class loader:最頂級的class loader,採用native code實現,是JVM的一部分;它負責加載核心的Java包,如java.lang.*、java.uti.*等; 這些類位於$JAVA_HOME/jre/lib/rt.jar;
Extension class loader:擴展的class loader,加載位於$JAVA_HOME/jre/lib/ext目錄下的擴展jar;
System class loader:系統class loader,加載$CLASSPATH下的目錄和jar;它負責加載應用程序主函數類;
二、Tomcat中的類加載
當一個Servlet直接代理類裝載請求給System class loader,則一個Context會加載其它Context下的類;所以每一個Context必需要有本身的類裝載器,用於裝載WEB-INF/classes和WEB-INF/lib下的類;
當Context須要裝載類時,先試着裝載位於WEB-INF/classes和WEB-INF/lib下的類;若是裝載失敗,則再代理給上級class loader;
Common class loader:負責裝載$CATALINA_HOME/common目錄下的全部類和jar包,詳細的配置可參考$CATALINA_HOME/conf/catalina.properties文件中的common.loader配置;該class loader裝載的類對於Server class loader和Webapp class loader是可見的;Common class loader在Tomcat啓動時建立,其parent class loader是System class loader;
Server class loader:負責裝載Tomcat的核心類,位於$CATALINE_HOME/server目錄下的全部類和jar,可由catalina.propreties中的server.loader配置指定;它在Tomcat啓動時被建立,其parent loader是Common class loader;
Shared class loader:負責裝載web app公用的類,能夠用戶經過catalina.properties文件中的shared.loader屬性來指定;它在Tomcat啓動時被建立,其parent loader也是Common class loader;
Webapp class loader:這個比較特殊,它只負責加載各自app中WEB-INF/classes以及WEB-INF/lib下的類;其parent loader雖然是Shared class loader,但其加載策略和默認的類加載機制不太同樣;
三、Webapp class loader
其類加載策略以下:
1) 先看以前有沒有加載過此類,若是加載過,直接從緩存中取出Class;
2) 若是以前沒有加載過,則直接委託System class loader加載(防止應用程序替換信任類),而System class loader會按默認的雙親委派模式加載;
3) 若是System class loader加載失敗,則試圖在當前應用程序的WEB-INF/classes和WEB-INF/lib目錄下加載(對於一些特殊的類,可能會先委託給Shared class loader加載);
4) 若是本身加載失敗,則最後委託給Shared class loader加載;
簡單畫了一下加載順序,能夠參考一下: