JDK9引入了Java模塊化系統(Java Platform Moudle System)來實現可配置的封裝隔離機制,同時JVM對類加載的架構也作出了調整,也就是雙親委派模型的第四次破壞。前三次破壞分別是:雙親委派模型推出以前,SPI機制,以及OSGI爲表明的熱替換機制,這裏不細說。java
在JDK9引入以前,絕大多數Java程序會用下面三個類加載器進行加載數據結構
若是一個ClassLoader收到了類加載的請求,他會先首先將請求委派給父類加載器完成,只有父類加載器加載不了,子加載器纔會完成加載。架構
下面代碼保留了核心邏輯,並添加了註釋,主要是2個步驟併發
Class<?> c = findLoadedClass(name);
//若是該類沒加載過
if (c == null) {
try {
//若是有父類加載器
if (parent != null) {
//使用父類加載器加載
c = parent.loadClass(name, false);
...
}
}
if (c == null) {
...
//父類加載器沒有加載成功則調用自身的findClass進行加載
c = findClass(name);
...
}
}
複製代碼
值得注意的是這裏的parent並非繼承上的父子關係,而是組合關係的父子,parent只是類加載器的一個參數。app
若是以爲上面的解釋比較抽象能夠看看下面比較形象的圖示,這裏的敵人就是咱們要加載的jar包maven
經過上面的漫畫不言而喻,當真正的敵人來了,靠這種低效的傳達機制,怎麼可能打一場勝仗呢?模塊化
既然一切都是各司其職,爲何不能加載類的時候一步到位呢?源碼分析
經過分析JDK9的類加載器源碼,我發現最新的類加載器結構在必定程度上是緩解了這種狀況的ui
在JDK9以前,JVM的基礎類之前都是在rt.jar這個包裏,這個包也是JRE運行的基石。這不只是違反了單一職責原則,一樣程序在編譯的時候會將不少無用的類也一併打包,形成臃腫。spa
在JDK9中,整個JDK都基於模塊化進行構建,之前的rt.jar, tool.jar被拆分紅數十個模塊,編譯的時候只編譯實際用到的模塊,同時各個類加載器各司其職,只加載本身負責的模塊。
Class<?> c = findLoadedClass(cn);
if (c == null) {
// 找到當前類屬於哪一個模塊
LoadedModule loadedModule = findLoadedModule(cn);
if (loadedModule != null) {
//獲取當前模塊的類加載器
BuiltinClassLoader loader = loadedModule.loader();
//進行類加載
c = findClassInModuleOrNull(loadedModule, cn);
} else {
// 找不到模塊信息纔會進行雙親委派
if (parent != null) {
c = parent.loadClassOrNull(cn);
}
}
複製代碼
上面代碼就是破壞雙親委派模型的「鐵證」,而當咱們繼續跟進findLoadedModule,會發現是根據路徑名找到對應的模塊,而維護這一數據結構的就是下面這個Map。
Map<String, LoadedModule> packageToModule
= new ConcurrentHashMap<>(1024);
複製代碼
能夠看到LoadedModule裏面不只有該模塊的loader信息,還有用於描述依賴模塊,對外暴露模塊的信息的mref,LoadedModule也是模塊化實現封裝隔離機制的一塊重要實現。
每個module信息都有一個BuiltinClassloader,這個類有三個子類,咱們經過源碼分析他們的父子關係
在ClassLoaders類中能夠發現,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);
}
}
複製代碼
通過破壞後的雙親委派模型更加高效,減小了不少類加載器之間沒必要要的委派操做
JDK9的模塊化能夠減小Java程序打包的體積,同時擁有更好的隔離線與封裝性
每一個moudle擁有專屬的類加載器,程序在併發性上也會更加出色
若是您以爲個人文章有用請點一個贊給予我支持!
複製代碼