Tomcat實現自定義類加載器


什么是類加載器?

  • 這是官方給的定義

image

在 Java 虛擬機的實現中,初始類可以作為命令行參數提供。 或者,該實現可以提供一個初始類,該類設置一個類加載器,該類加載器依次加載應用程序。 初始類的其他選擇也是可能的,只要它們與上一段中給出的規范一致。

所謂類加載器,就是用於加載Java類到Java虛擬機中的組件,它負責讀取Java字節碼,並轉換成java.lang.Class類的一個實例,使字節碼.class 文件得以運行。一般類加載器負責根據一個指定的類找到對應的字節碼,然后根據這些字節碼定義一個Java類。
類加載器在實際使用中給我們帶來的好處是,它可以使Java類動態地加載到JVM中並運行,即可在程序運行時再加載類,提供了很靈活的動態加載方式。

站在程序員的角度來看,Java 類加載器可以分為三種。

  • 啟動類加載器(Bootstrap ClassLoader):加載對象是Java核心庫,把一些核心的Java類加載進JVM中,這個加載器使用原生代碼(C/C++)實現,並不是繼承java.lang.ClassLoader,它是所有其他類加載器的最終父加載器,負責加載<JAVA_HOME>/jre/lib目錄下JVM指定的類庫。其實它屬於JVM整體的一部分,JVM一啟動就將這些指定的類加載到內存中,避免以后過多的I/O操作,提高系統的運行效率。啟動類加載器無法被Java程序直接使用。
  • 擴展類加載器(Extension ClassLoader):加載的對象為Java的擴展庫,即加載<JAVA_HOME>/jre/lib/ext目錄里面的類。這個類由啟動類加載器加載,但因為啟動類加載器並非用Java 實現,已經脫離了Java體系,所以如果嘗試調用擴展類加載器的getParent()方法獲取父加載器會得到null。然而,它的父類加載器是啟動類加載器。
  • 應用程序類加載器((Application ClassLoader):亦叫系統類加載器(System ClassLoader),它負責加載用戶類路徑(CLASSPATH)指定的類庫,如果程序沒有自己定義類加載器,就默認使用應用程序類加載器。它也由啟動類加載器加載,但它的父加載類被設置成了擴展類加載器。如果要使用這個加載器,可通過ClassLoader.getSystemClassLoader()獲取。

雙親委派
雙親委派模型會在類加載器加載類時首先委托給父類加載器加載,除非父類加載器不能加載才自己加載。
使用雙親委派模型,Java類隨着它的加載器一起具備了一種帶有優先級的層次關系,通過這種層次模型,可以避免類的重復加載,也可以避免核心類被不同的類加載器加載到內存中造成沖突和混亂,從而保證了Java核心庫的安全。

img

  • 示范

image

最頂級的類加載器Bootstrap是由c++語言寫的,所以打印出來是Null

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=2921:D:\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;
后面的這些就是應用類加載器
D:\original\apache-tomcat-8.5.70-src\target\classes;D:\software\maven_repository\org\easymock\easymock\3.4\easymock-3.4.jar;D:\software\maven_repository\org\objenesis\objenesis\2.2\objenesis-2.2.jar;D:\software\maven_repository\org\apache\ant\ant\1.7.0\ant-1.7.0.jar;D:\software\maven_repository\org\apache\ant\ant-launcher\1.7.0\ant-launcher-1.7.0.jar;D:\software\maven_repository\wsdl4j\wsdl4j\1.6.2\wsdl4j-1.6.2.jar;D:\software\maven_repository\javax\xml\jaxrpc-api\1.1\jaxrpc-api-1.1.jar;D:\software\maven_repository\org\eclipse\jdt\core\compiler\ecj\4.5.1\ecj-4.5.1.jar" org.apache.catalina.startup.Test
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@29453f44
null

Process finished with exit code 0

為什么TOMCAT要破壞雙親委派?

我們知道,Tomcat是web容器,那么一個web容器可能需要部署多個應用程序。

不同的應用程序可能會依賴同一個第三方類庫的不同版本,但是不同版本的類庫中某一個類的全路徑名可能是一樣的。

如多個應用都要依賴hollis.jar,但是A應用需要依賴1.0.0版本,但是B應用需要依賴1.0.1版本。這兩個版本中都有一個類是com.hollis.Test.class。

如果采用默認的雙親委派類加載機制,那么是無法加載多個相同的類。

所以,Tomcat破壞雙親委派原則,提供隔離的機制,為每個web容器單獨提供一個WebAppClassLoader加載器。

Tomcat是怎么破壞雙親委派的呢?

  • 通過實現自定義加載器

Tomcat 本身有commonclassloader來管理,不去跟應用程序所沖突

每一個應用都會生成一個類加載器的實例 webclassloader

管理一個目錄 這個目錄 就是web-inf

這個目錄由findclassloader來指定

webclassloader的上一級類加載器就是commonclassloader

整個層級關系就是這樣的

雙親委派變五親委派(不是

webclassloader-->commonclassloader-->appclassloader-->extclassloader-->bootstrapclassloader

Tomcat的類加載機制:為了實現隔離性,優先加載 Web 應用自己定義的類,所以沒有遵照雙親委派的約定,每一個應用自己的類加載器——WebAppClassLoader負責加載本身的目錄下的class文件,加載不到時再交給CommonClassLoader加載,這和雙親委派剛好相反。

image

怎么實現一個自定義加載器

  1. 繼承Classloder接口

image

  1. 重寫構造方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM