模块化加载_Java9模块化的类加载机制实现剖析
前言
JDK9引入了Java模塊化系統(tǒng)(Java Platform Moudle System)來(lái)實(shí)現(xiàn)可配置的封裝隔離機(jī)制,同時(shí)JVM對(duì)類(lèi)加載的架構(gòu)也做出了調(diào)整,也就是雙親委派模型的第四次破壞。前三次破壞分別是:雙親委派模型推出之前,SPI機(jī)制,以及OSGI為代表的熱替換機(jī)制,這里不細(xì)說(shuō)。
雙親委派模型
簡(jiǎn)介
在JDK9引入之前,絕大多數(shù)Java程序會(huì)用下面三個(gè)類(lèi)加載器進(jìn)行加載
- 啟動(dòng)類(lèi)加載器(Bootstrap Class Loader):由C++編寫(xiě),負(fù)責(zé)加載jrelib目錄下的類(lèi),例如最基本的Object,Integer,這些存在于rt.jar文件中的類(lèi),一般這些類(lèi)都是Java程序的基石。
- 擴(kuò)展類(lèi)加載器(Extension Class Loader):負(fù)責(zé)加載jrelibext目錄下的類(lèi),在JDK9之前我們可以將通用性的類(lèi)庫(kù)放在ext目錄來(lái)擴(kuò)展JAVA的功能,但實(shí)際的工程都是通過(guò)maven引入jar包依賴(lài)。并且在JDK9取消了這一類(lèi)加載器,取而代之的是平臺(tái)類(lèi)加載器(Platform Class Loader),下面會(huì)對(duì)其介紹。
- 應(yīng)用類(lèi)加載器(Application Class Loader):負(fù)責(zé)加載ClassPath路徑下的類(lèi),通常工程師編寫(xiě)的大部分類(lèi)都是由這個(gè)類(lèi)加載器加載。
工作順序
解釋
如果一個(gè)ClassLoader收到了類(lèi)加載的請(qǐng)求,他會(huì)先首先將請(qǐng)求委派給父類(lèi)加載器完成,只有父類(lèi)加載器加載不了,子加載器才會(huì)完成加載。
源代碼
下面代碼保留了核心邏輯,并添加了注釋,主要是2個(gè)步驟
值得注意的是這里的parent并不是繼承上的父子關(guān)系,而是組合關(guān)系的父子,parent只是類(lèi)加載器的一個(gè)參數(shù)。
圖示
如果覺(jué)得上面的解釋比較抽象可以看看下面比較形象的圖示,這里的敵人就是我們要加載的jar包
缺點(diǎn)
通過(guò)上面的漫畫(huà)不言而喻,當(dāng)真正的敵人來(lái)了,靠這種低效的傳達(dá)機(jī)制,怎么可能打一場(chǎng)勝仗呢?
- 啟動(dòng)類(lèi)加載器負(fù)責(zé)加載jrelib目錄
- 擴(kuò)展類(lèi)加載器負(fù)責(zé)加載jrelibext目錄
- 應(yīng)用類(lèi)加載器負(fù)責(zé)加載ClassPath目錄。
既然一切都是各司其職,為什么不能加載類(lèi)的時(shí)候一步到位呢?
通過(guò)分析JDK9的類(lèi)加載器源碼,我發(fā)現(xiàn)最新的類(lèi)加載器結(jié)構(gòu)在一定程度上是緩解了這種情況的
JDK的模塊化
在JDK9之前,JVM的基礎(chǔ)類(lèi)以前都是在rt.jar這個(gè)包里,這個(gè)包也是JRE運(yùn)行的基石。這不僅是違反了單一職責(zé)原則,同樣程序在編譯的時(shí)候會(huì)將很多無(wú)用的類(lèi)也一并打包,造成臃腫。
在JDK9中,整個(gè)JDK都基于模塊化進(jìn)行構(gòu)建,以前的rt.jar, tool.jar被拆分成數(shù)十個(gè)模塊,編譯的時(shí)候只編譯實(shí)際用到的模塊,同時(shí)各個(gè)類(lèi)加載器各司其職,只加載自己負(fù)責(zé)的模塊。
模塊化加載源碼
Class> c = findLoadedClass(cn); if (c == null) { // 找到當(dāng)前類(lèi)屬于哪個(gè)模塊 LoadedModule loadedModule = findLoadedModule(cn); if (loadedModule != null) { //獲取當(dāng)前模塊的類(lèi)加載器 BuiltinClassLoader loader = loadedModule.loader(); //進(jìn)行類(lèi)加載 c = findClassInModuleOrNull(loadedModule, cn); } else { // 找不到模塊信息才會(huì)進(jìn)行雙親委派 if (parent != null) { c = parent.loadClassOrNull(cn); } }上面代碼就是破壞雙親委派模型的“鐵證”,而當(dāng)我們繼續(xù)跟進(jìn)findLoadedModule,會(huì)發(fā)現(xiàn)是根據(jù)路徑名找到對(duì)應(yīng)的模塊,而維護(hù)這一數(shù)據(jù)結(jié)構(gòu)的就是下面這個(gè)Map。
Map packageToModule = new ConcurrentHashMap<>(1024);可以看到LoadedModule里面不僅有該模塊的loader信息,還有用于描述依賴(lài)模塊,對(duì)外暴露模塊的信息的mref,LoadedModule也是模塊化實(shí)現(xiàn)封裝隔離機(jī)制的一塊重要實(shí)現(xiàn)。
每一個(gè)module信息都有一個(gè)BuiltinClassloader,這個(gè)類(lèi)有三個(gè)子類(lèi),我們通過(guò)源碼分析他們的父子關(guān)系
在ClassLoaders類(lèi)中可以發(fā)現(xiàn),PlatformClassLoader的parent是BootClassLoader,而AppClassLoader的parent則是PlatformClassLoader。
public class ClassLoaders { // the built-in class loaders private static final BootClassLoader BOOT_LOADER; private static final PlatformClassLoader PLATFORM_LOADER; private static final AppClassLoader APP_LOADER; static { BOOT_LOADER = new BootClassLoader((append != null && !append.isEmpty()) ? new URLClassPath(append, true) : null); PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER); ... APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp); } }結(jié)論
總結(jié)
以上是生活随笔為你收集整理的模块化加载_Java9模块化的类加载机制实现剖析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 网商贷降额度原因 网商贷降额度的原因
- 下一篇: ps如何制作表格?(如何制作好看的表格)