本文將以四個問題展開:java
類加載機制一個很大的體系,包括類加載的時機,類加載器,類加載時機。web
加載器加載到jvm中,接下來其實又分了好幾個步驟:緩存
1)驗證,文件格式、元數據、字節碼、符號引用驗證;
2)準備,爲類的靜態變量分配內存,並將其初始化爲默認值;
3)解析,把類中的符號引用轉換爲直接引用tomcat
如今咱們例子中生成的兩個.class
文件都會直接被加載到JVM中嗎??安全
虛擬機規範則是嚴格規定了有且只有5種狀況必須當即對類進行「初始化」(class文件加載到JVM中):服務器
因此說:markdown
各個加載器的工做責任:app
工做過程:jvm
1.3的回答其實這就是所謂的雙親委派模型。簡單來講:若是一個類加載器收到了類加載的請求,它首先不會本身去嘗試加載這個類,而是把請求委託給父加載器去完成,依次向上。jsp
好處:
特別說明:
java.lang.Class
類的實例緩存起來。下次再請求加載該類的時候,類加載器會直接使用緩存的類的實例,而不會嘗試再次加咱們說,雙親委派模型很好的解決了各個類加載器的基礎類的統一問題(越基礎的類由越上層的加載器進行加載),基礎類之因此稱爲「基礎」,是由於它們老是做爲被用戶代碼調用的API, 但沒有絕對,若是基礎類調用會用戶的代碼怎麼辦呢? 這不是沒有可能的。
一個典型的例子就是JNDI服務,JNDI如今已是Java的標準服務,它的代碼由啓動類加載器去加載(在JDK1.3時就放進去的rt.jar),但它須要調用由獨立廠商實現並部署在應用程序的ClassPath下的JNDI接口提供者(SPI, Service Provider Interface)
的代碼,但啓動類加載器不可能「認識「這些代碼啊。由於這些類不在rt.jar中,可是啓動類加載器又須要加載。怎麼辦呢?
爲了解決這個問題,Java設計團隊只好引入了一個不太優雅的設計:線程上下文類加載器(Thread Context ClassLoader)
。這個類加載器能夠經過java.lang.Thread
類的setContextClassLoader
方法進行設置。若是建立線程時還未設置,它將會從父線程中繼承一個,若是在應用程序的全局範圍內都沒有設置過多的話,那這個類加載器默認即便應用程序類加載器。
有了線程上下文加載器,JNDI服務使用這個線程上下文加載器去加載所須要的SPI代碼,也就是父類加載器請求子類加載器去完成類加載的動做,這種行爲實際上就是打通了雙親委派模型的層次結構來逆向使用類加載器,實際上已經違背了雙親委派模型的通常性原則。但這迫不得已,Java中全部涉及SPI的加載動做基本勝都採用這種方式。例如JNDI,JDBC,JCE,JAXB,JBI等。
自定義類加載器,而且重寫ClassLoader類的loadClass()
首先,咱們來問個問題: Tomcat 若是使用默認的類加載機制行不行? 咱們思考一下:Tomcat是個web容器, 那麼它要解決什麼問題:
再看看咱們的問題:Tomcat 若是使用默認的類加載機制行不行? 答案是不行的。爲何?咱們看,第一個問題,若是使用默認的類加載器機制,那麼是沒法加載兩個相同類庫的不一樣版本的,默認的累加器是無論你是什麼版本的,只在意你的全限定類名,而且只有一份。第二個問題,默認的類加載器是可以實現的,由於他的職責就是保證惟一性。第三個問題和第一個問題同樣。咱們再看第四個問題,咱們想咱們要怎麼實現jsp文件的熱修改,jsp 文件其實也就是class文件,那麼若是修改了,但類名仍是同樣,類加載器會直接取方法區中已經存在的,修改後的jsp是不會從新加載的。那麼怎麼辦呢?咱們能夠直接卸載掉這jsp文件的類加載器,因此你應該想到了,每一個jsp文件對應一個惟一的類加載器,當一個jsp文件修改了,就直接卸載這個jsp類加載器。從新建立類加載器,從新加載jsp文件。 Tomcat 如何實現本身獨特的類加載機制? 因此,Tomcat 是怎麼實現的呢?牛逼的Tomcat團隊已經設計好了。咱們看看他們的設計圖:
咱們看到,前面3個類加載和默認的一致,CommonClassLoader
、CatalinaClassLoader
、SharedClassLoader
和WebappClassLoader
則是Tomcat本身定義的類加載器,它們分別加載/common/*、/server/*、/shared/*(在tomcat 6以後已經合併到根目錄下的lib目錄下)和/WebApp/WEB-INF/*中的Java類庫。
其中WebApp類加載器和Jsp類加載器一般會存在多個實例,每個Web應用程序對應一個WebApp類加載器,
commonLoader
:Tomcat最基本的類加載器,加載路徑中的class能夠被Tomcat容器自己以及各個Webapp訪問;
catalinaLoader
:Tomcat容器私有的類加載器,加載路徑中的class對於Webapp不可見;
sharedLoader
:各個Webapp共享的類加載器,加載路徑中的class對於全部Webapp可見,可是對於Tomcat容器不可見;
WebappClassLoader
:各個Webapp私有的類加載器,加載路徑中的class只對當前Webapp可見
JasperLoader
:每個JSP文件對應一個Jsp類加載器