天天看點

Tomcat:類加載機制剖析

作者:日拱一卒程式猿

一、背景

Java類(.java)—> 位元組碼檔案(.class) —> 位元組碼檔案需要被加載到jvm記憶體當中(這個過程就是一個類加載的過程)

類加載器(ClassLoader,說白了也是一個類,jvm啟動的時候先把類加載器讀取到記憶體當中去,其他的類(比如各種jar中的位元組碼檔案,自己開發的代碼編譯之後的.class檔案等等))

要說 Tomcat 的類加載機制,首先需要來看看 Jvm 的類加載機制,因為 Tomcat 類加載機制是在 Jvm 類加載機制基礎之上進行了一些變動

二、Jvm類加載機制

JVM 的類加載機制中有一個非常重要的角色叫做類加載器(ClassLoader),

類加載器有自己的體系,Jvm内置了幾種類加載器,包括:引導類加載器、擴充類加載器、系統類加載器,他們之間形成父子關系,通過 Parent 屬性來定義這種關系,最終可以形成樹形結構。

Tomcat:類加載機制剖析
Tomcat:類加載機制剖析

另外:使用者可以自定義類加載器(Java編寫,使用者自定義的類加載器,可加載指定路徑的 class 檔案) 

當 JVM 運作過程中,使用者自定義了類加載器去加載某些類時,會按照下面的步驟(父類委托機制)  

1) 使用者自己的類加載器,把加載請求傳給父加載器,父加載器再傳給其父加載器,一直到加載器樹的頂層  

2 )最頂層的類加載器首先針對其特定的位置加載,如果加載不到就轉交給子類  

3 )如果一直到底層的類加載都沒有加載到,那麼就會抛出異常 ClassNotFoundException  是以,按照這個過程可以想到,如果同樣在 classpath 指定的目錄中和自己工作目錄中存放相同的class,會優先加載 classpath 目錄中的檔案

三、雙親委派機制

1、定義

當某個類加載器需要加載某個.class檔案時,它首先把這個任務委托給他的上級類加載器,遞歸這個操作,如果上級的類加載器沒有加載,自己才會去加載這個

2、作用

  • 防止重複加載同一個.class。通過委托去向上面問一問,加載過了,就不用再加載一遍。
  • 保證資料安全。保證核心.class不能被篡改。通過委托方式,不會去篡改核心.class,即使篡改也不會去加載,即使加載也不會是同一個.class對象了。不同的加載器加載同一個.class也不是同一個.class對象。這樣保證了class執行安全

(如果子類加載器先加載,那麼我們可以寫一些與java.lang包中基礎類同名的類, 然後再定義一個子類加載器,這樣整個應用使用的基礎類就都變成我們自己定義的類了。)Object類 -----> 自定義類加載器(會出現問題的,那麼真正的Object類就可能被篡改了)

四、Tomcat類加載機制

Tomcat 的類加載機制相對于 Jvm 的類加載機制做了一些改變。

沒有嚴格的遵從雙親委派機制,也可以說打破了雙親委派機制。

比如:有一個tomcat,webapps下部署了兩個應用

app1/lib/a-1.0.jar com.lagou.edu.Abc

app2/lib/a-2.0.jar com.lagou.edu.Abc

不同版本中Abc類的内容是不同的,代碼是不一樣。

Tomcat:類加載機制剖析
  • 引導類加載器 和 擴充類加載器 的作用不變
  • 系統類加載器正常情況下加載的是 CLASSPATH 下的類,但是 Tomcat 的啟動腳本并未使用該變量,而是加載tomcat啟動的類,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下
  • Common 通用類加載器加載Tomcat使用以及應用通用的一些類,位于CATALINA_HOME/lib下,比如servlet-api.jar
  • Catalina ClassLoader 用于加載伺服器内部可見類,這些類應用程式不能通路
  • Shared ClassLoader 用于加載應用程式共享類,這些類伺服器不會依賴Webapp ClassLoader,每個應用程式都會有一個獨一無二的
  • Webapp ClassLoader,他用來加載本應用程式 /WEB-INF/classes 和 /WEB-INF/lib 下的類。

tomcat 8.5 預設改變了嚴格的雙親委派機制

首先從 Bootstrap Classloader加載指定的類

如果未加載到,則從 /WEB-INF/classes加載

如果未加載到,則從 /WEB-INF/lib/*.jar 加載

繼續閱讀