談談 Java 類載入機制
最近在學習 Tomcat 架構,其中很重要的一個模組是類載入器,因為以前學習的不夠深入,所以趁這個機會好好把類載入機制搞明白。
概述
類載入器主要分為兩類,一類是 JDK 預設提供的,一類是使用者自定義的。 JDK 預設提供三種類載入器:
Bootstrap ClassLoader 啟動類載入器:每次執行 java 命令時都會使用該載入器為虛擬機器載入核心類。該載入器是由 native code 實現,而不是 Java 程式碼,載入類的路徑為 /jre/lib。特別的 /jre/lib/rt.jar 中包含了 sun.misc.Launcher 類, 而 sun.misc.LauncherAppClassLoader 都是 sun.misc.Launcher 的內部類,所以拓展類載入器和系統類載入器都是由啟動類載入器載入的。
Extension ClassLoader, 拓展類載入器:用於載入拓展庫中的類。拓展庫路徑為 /jre/lib/ext/。實現類為 sun.misc.Launcher$ExtClassLoader
SystemClassLoader系統類載入器:用於載入 CLASSPATH 中的類。實現類為 sun.misc.Launcher$AppClassLoader
使用者自定義的類載入器
Custom ClassLoader, 一般都是 java.lang.ClassLoder 的子類
正統的類載入機制是基於雙親委派的,也就是當呼叫類載入器載入類時,首先將載入任務委派給雙親,若雙親無法載入成功時,自己才進行類載入。
在例項化一個新的類載入器時,我們可以為其指定一個 parent,即雙親,若未顯式指定,則 System ClassLoader 就作為預設雙親。
具體的說,類載入任務是由 ClassLoader 的 loadClass() 方法來執行的,他會按照以下順序載入類:
通過 findLoadedClass() 看該類是否已經被載入。該方法為 native code 實現,若已載入則返回。
若未載入則委派給雙親,parent.loadClass(),若成功則返回。
若未成功,則呼叫 findClass() 方法載入類。java.lang.ClassLoader 中該方法只是簡單的丟擲一個 ClassNotFoundException 所以,自定義的 ClassLoader 都需要 Override findClass() 方法。
類載入API
java.lang.ClassLoader
ClassLoader 是一個抽象類。
待載入的類必須用 The Java™ Language Specification 定義的全類名,全類名的定義請查閱 The Form of a Binary。
給定一個全類名,類載入器應該去定位該類所在的位置。通用的策略是將全類名轉換為類檔案路徑,然後通過類檔案路徑在檔案系統中定位。
每一個載入到記憶體的類都由一個 Class 物件來表示,每一個 Class 物件都有一個指向載入該類的類載入器的引用。但是陣列的 Class 物件是由 Java 執行時環境建立的,通過 Class.getClassLoader() 方法返回的是陣列元素的類載入器,若陣列元素是基本型別,則返回 null,若類是由 Bootstrap ClassLoader 載入的話也是返回 null。
public class Main {
public static void main(String[] args) {
// Object 類在 <java_home>/jre/lib/rt.jar 中,
// 由 Bootstrap ClassLoader 載入,由於該類載入器是由 native code 編寫
// 所以輸出為 null
Object[] objects = new Object[5];
System.out.println();
System.out.println(objects.getClass().getClassLoader());
// ZipFileAttributes 類在 <java_home>/jre/lib/ext/zipfs.jar 中,
// 由 Extension ClassLoader 載入,
// 輸出為 [email protected]
ZipFileAttributes[] attributes = new ZipFileAttributes[5];
System.out.println();
System.out.println(attributes.getClass().getClassLoader());
// Main 類是自定義的類,
// 預設由 System ClassLoader 載入,
// 輸出為 [email protected]
Main[] array = new Main[5];
array[0] = new Main();
System.out.println();
System.out.println(array.getClass().getClassLoader());
}
}
ClassLoader 預設支援並行載入,但是其子類必須呼叫 ClassLoader.registerAsParallelCapable() 來啟用並行載入
一般來說,JVM 從本地檔案系統載入類的行為是與平臺有關的。
defineClass() 方法可以將位元組流轉換成一個 Class 物件。然後呼叫 Class.newInstance() 來建立類的例項
java.security.SecureClassLoader
增加了一層許可權驗證,因為關注點不在安全,所以暫不討論。
java.net.URLClassLoader
該類載入器用來載入 URL 指定的 JAR 檔案或目錄中的類和資源,以 / 結尾的 URL 認為是目錄,否則認為是 JAR 檔案。
// 嘗試通過 URLClassLoader 來載入桌面下的 Test 類。
public class Main {
public static void main(String[] args) {
try {
URL[] urls = new URL[1];
URLStreamHandler streamHandler = null;
File classPath = new File("/home/chen/Desktop/");
String repository = (new URL("file", null,
classPath.getCanonicalPath() + File.separator))
.toString();
urls[0] = new URL(null, repository, streamHandler);
ClassLoader loader = new URLClassLoader(urls);
Class testClass = loader.loadClass("Test");
// output: [email protected]
System.out.println(testClass.getClassLoader());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Tomcat 8.5.15類載入機制
Tomcat 使用正統的類載入機制(雙親委派),但部分地方做了改動。
Bootstrap classLoader 和 Extension classLoader 的作用不變。
System classLoader 正常情況下載入的是 CLASSPATH 下的類,但是 Tomcat 的啟動指令碼並未使用該變數,而是從以下倉庫下載入類:
$CATALINA_HOME/bin/bootstrap.jar 包含了 Tomcat 的啟動類。在該啟動類中建立了 Common classLoader、Catalina classLoader、shared classLoader。因為 $CATALINA_BASE/conf/catalina.properties 中只對 common.loader 屬性做了定義,server.loader 和 shared.loader 屬性為空,所以預設情況下,這三個 classLoader 都是 CommonLoader。具體的程式碼邏輯可以查閱 org.apache.catalina.startup.Bootstrap 類的 initClassLoaders() 方法和 createClassLoader() 方法。
$CATALINA_BASE/bin/tomcat-juli.jar 包含了 Tomcat 日誌模組所需要的實現類。
$CATALINA_HOME/bin/commons-daemon.jar。
Common classLoader 是位於 Tomcat 應用伺服器頂層的公用類載入器。由其載入的類可以由 Tomcat 自身類和所有應用程式使用。掃描路徑由 $CATALINA_BASE/conf/catalina.properties 檔案中的 common.loader 屬性定義。預設是 $CATALINA_HOME/lib。
catalina classLoader 用於載入伺服器內部可見類,這些類應用程式不能訪問。
shared classLoader 用於載入應用程式共享類,這些類伺服器不會依賴。
Webapp classLoader 。每個應用程式都會有一個獨一無二的 webapp classloader,他用來載入本應用程式 /WEB-INF/classes 和 /WEB-INF/lib 下的類。
特別的:
Webapp classLoader 的預設行為會與正常的雙親委派模式不同:
從 Bootstrap classloader 載入。
若沒有,從 /WEB-INF/classes 載入。
若沒有,從 /WEB-INF/lib/*.jar 載入。
若沒有,則依次從 System、Common、shared 載入(該步驟使用雙親委派)。
當然了,我們也可以通過配置來使 Webapp classLoader 嚴格按照雙親委派模式載入類:
通過在工程的 META-INF/context.xml(和 WEB-INF/classes 在同一目錄下) 配置檔案中新增
因為 Webapp classLoader 的實現類是 org.apache.catalina.loader.WebappLoader,他有一個屬性叫 delegate, 用來控制類載入器的載入行為,預設為 false,我們可以使用 set 方法,將其設為 true 來啟用嚴格雙親委派載入模式。
嚴格雙親委派模式載入步驟:
從 Bootstrap classloader 載入。
若沒有,則依次從 System、Common、shared 載入。
若沒有,從 /WEB-INF/classes 載入。
若沒有,從 /WEB-INF/lib/*.jar 載入。
歡迎工作一到五年的Java工程師朋友們加入Java程式設計師開發: 854393687
群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
相關推薦
談談 Java 類載入機制
最近在學習 Tomcat 架構,其中很重要的一個模組是類載入器,因為以前學習的不夠深入,所以趁這個機會好好把類載入機制搞明白。 概述 類載入器主要分為兩類,一類是 JDK 預設提供的,一類是使用者自定義的。 JDK 預設提供三種類載入器: Bootstrap
從阿里巴巴面試題到java類載入機制
首先很經典的阿里巴巴面試題 加上我自己的一些疑惑程式碼 public class Text { public static int k = 0; public final int k1 = 3; //自己加的 public static Text t1 = new Text("
java類載入機制和自定義類載入器
類載入順序 上圖所示的是類載入的順序,按照大的順序可以分為載入、連結、初始化 其中連結又可以分成驗證、準備、解析三個步驟 載入 1.將類的class檔案讀入到記憶體中 載入類檔案的方式有: 1. 本機檔案載入 2.jar包載入 3.網路載入 4.原始檔動態編譯載入
淺談Java類載入機制
最近在學習 Tomcat 架構,其中很重要的一個模組是類載入器,因為以前學習的不夠深入,所以趁這個機會好好把類載入機制搞明白。 概述 類載入器主要分為兩類,一類是 JDK 預設提供的,一類是使用者自定義的。 JDK 預設提供三種類載入器 Bootstrap ClassLo
深入理解Java類載入機制(一)
1 前言: 在上一篇文章一文讓你明白 Java 位元組碼中, 我們瞭解了java位元組碼的解析過程,那麼在接下來的內容中,我們來了解一下類的載入機制。 2 題外話 Java的核心是什麼?當然是JVM了,所以說了解並熟悉JVM對於我們理解Java語言非常重要,不管你是做Java還是Andr
Java 類載入機制詳解
一、類載入器 類載入器(ClassLoader),顧名思義,即載入類的東西。在我們使用一個類之前,JVM需要先將該類的位元組碼檔案(.class檔案)從磁碟、網路或其他來源載入到記憶體中,並對位元組碼進行解析生成對應的Class物件,這就是類載入器的功能。我們可以利用類載入器,實現類的動態載入。 二、類的
Java類載入機制
類載入機制 概念 類載入器把class檔案中的二進位制資料讀入到記憶體中,存放在方法區,然後在堆區建立一個java.lang.Class物件,用來封裝類在方法區內的資料結構。 1、載入: 查詢並載入類的二進位制資料(把class檔案裡面的資訊載入到記憶體裡面) 2
JVM——Java類載入機制
class Singleton{ private static Singleton singleton = new Singleton(); public static int value1; public static int valu
JAVA 類載入機制學習筆記
JAVA 類生命週期 如上圖所示,Java類的生命週期如圖所示,分別為載入、驗證、準備、解析、初始化、使用、解除安裝。其中驗證、準備、解析這三個步驟統稱為連結。 載入:JVM根據全限定名來獲取一段二進位制位元組流,將二進位制流轉化為方法區的執行時資料結構,在記憶體中生成一個代表
【Java面試題】之類載入:從面試題分析Java類載入機制
“載入”(Loading)階段是“類載入”(Class Loading)過程的第一個階段,在此階段,虛擬機器需要完成以下三件事情: 1、 通過一個類的全限定名來獲取定義此類的二進位制位元組流。 2、 將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結
jvm之java類載入機制和類載入器(ClassLoader)的詳解
當程式主動使用某個類時,如果該類還未被載入到記憶體中,則JVM會通過載入、連線、初始化3個步驟來對該類進行初始化。如果沒有意外,JVM將會連續完成3個步驟,所以有時也把這個3個步驟統稱為類載入或類初始化。
Java-類載入機制
Java-類載入機制 摘要 本文簡要介紹Java載入機制,還會介紹雙親委派機制的破壞,執行緒上下文載入器,以及JDBC Driver是如何自動載入的。 未完成 0x01 Java類載入機制 1.1 簡介 當前版本jdk是採用雙親委派機制: 子ClassL
java 類載入機制--類載入時機
相對於看很多父類和子類如何如何初始化的文章,瞭解java虛擬機器的類載入機制之後都會覺得,噢,原來是這個樣子!這裡僅就類的載入時機做個學習筆記,更多內容改日再寫。詳情請看《深入理解java虛擬機器》。 不同於例如c,cpp那些編譯時期就需要進行連線工作的語言,
Java 類載入機制 ClassLoader Class.forName 記憶體管理 垃圾回收GC
類載入是Java程式執行的第一步,研究類的載入有助於瞭解JVM執行過程,並指導開發者採取更有效的措施配合程式執行。 研究類載入機制的第二個目的是讓程式能動態的控制類載入,比如熱部署等,提高程式的靈活性和適應性。 一、簡單過程 Java
Java類載入機制——案例分析
原文連結:http://blog.csdn.net/u013256816/article/details/50837863 在《Java虛擬機器類載入機制》一文中詳細闡述了類載入的過程,並舉了幾個例子進行了簡要分析,在文章的最後留了一個懸念給各位,這裡來揭開這個懸念。建
深入java static關鍵字 淺析java類載入機制(解答java靜態方法或變數無法訪問非靜態資料)
想要清晰理解java語法,不瞭解java和jvm的機制是不行的,以前不理解java中用static修飾方法和變數為什麼不可以訪問非靜態方法和資料,現在明瞭,如果你也有相同的困惑,這篇部落格足以解惑,原創不易,轉載請宣告出處。 本文分為3大部分 static
java 類載入機制
1.java虛擬機器中可以有多個類載入器。 2.系統預設有三個類載入器,每個類載入器負責特定的位置的類載入任務,分別是: BootStrap-->JRE/lib/rt.jar ExtClassLoader-->JRE/lib/ext/*.jar AppClass
阿里面試題,深入理解Java類載入機制
類的生命週期 包括以下 7 個階段: 載入(Loading) 驗證(Verification) 準備(Pr
技術複習-java類載入機制
java類載入過程 裝載 把class位元組碼載入到記憶體中。 連結 驗證、準備、解析 初始化 類的靜態變數、靜態程式碼庫
JVM 第三篇:Java 類載入機制
![](https://cdn.geekdigging.com/java/java_header.jpg) > 本文內容過於硬核,建議有 Java 相關經驗人士閱讀。 ## 1. 什麼是類的載入? 類的載入指的是將類的 .class 檔案中的二進位制資料讀入到記憶體中,將其放在執行時資料區的方法區內,然