類加載器和類加載過程
本篇主要內容:
- JVM工做結構簡圖。
- 類加載過程。
- 類加載器(ClassLoader)。
- 自定義類加載器實現步驟。
JVM工做結構簡圖
![JVM工做結構.png JVM工做結構.png](http://static.javashuo.com/static/loading.gif)
類加載過程
上圖中咱們看到了字節碼文件通過類加載子系統加載到JVM中,那麼如今咱們在看類加載子系統中發生了什麼。
先放一張類加載過程的簡圖。
![類加載過程.png 類加載過程.png](http://static.javashuo.com/static/loading.gif)
其中包括了三個大步驟,他們分別是:java
加載
加載指的是將類的class文件讀入到內存,併爲之建立一個java.lang.Class對象。安全
- 經過類的全限定名獲取此類的二進制字節流。
- 將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構。
- 在內存中生成一個Class對象,做爲方法區這個類的各類數據的訪問入口。
加載一般由類加載器完成,加載類的方式具體有如下幾項:網絡
- 本地資源加載。
- 網絡加載。Web Applet。
- zip壓縮包加載。jar,war。
- 運行時計算生成。動態代理技術。
- 其餘文件生成。JSP應用。
- 從加密文件中讀取,主要是爲了防止class文件被反編譯。
連接
連接分爲三個步驟:數據結構
- 驗證
確保class文件的字節流中包含信息符合虛擬機要求。
主要包括,文件格式驗證,元數據驗證,字節碼驗證,符號引用驗證。
- 準備
爲類變量分配內存,併爲變量賦零值。
這裏不包括用final修飾的static,由於final在變異的時候就會分配了,準備階段會顯式初始化。
不會爲實例變量分配初始化。
- 解析
將常量池內的符號引用變爲直接引用。
初始化
- 初始化階段就是執行類構造器方法<clinit>()方法。
- <clinit>()方法是由javac將類變量賦值動做和靜態代碼塊中的語句合併自動產生的。當類不存在類變量和靜態代碼塊時不會自動生成此方法。
- 一個類只會被加載一次,<clinint>()方法是同步加鎖的。(後付測試代碼)
注:若是想看此方法,能夠使用JClassLib軟件或IDEA中的JClassLib插件。
附一張clinit<>()方法圖和同步測試代碼。
測試
package cn.lele;
public class ClinitTest02 {
public static void main(String[] args) {
Runnable r = ()->{
System.out.println(Thread.currentThread().getName() + "start");
DeadThread deadThread = new DeadThread();
System.out.println(Thread.currentThread().getName() + "finish");
};
Thread a = new Thread(r,"A");
Thread b = new Thread(r,"B");
a.start();
b.start();
}
}
class DeadThread {
static {
if (true) {
System.out.println(Thread.currentThread().getName() + "初始化當前類");
while (true) {
}
}
}
}
圖中咱們看到在number聲明以前咱們就能夠在同步代碼塊中爲他賦值,這是由於在連接的準備階段,number變量已經分配了內存空間而且賦予了零值。加密
類加載器(ClassLoader)
類加載過程的第一步加載,是須要類加載器來完成的,Java爲咱們提供了三個類加載器來完成這一步。spa
引導類加載器
- 該引導器使用C/C++實現。
- 該引導器負責加載JAVA的核心類庫。
- 加載擴展類加載器和應用程序加載器,並制定爲他們的父加載器。
- 出於安全考慮,只會加載包名爲java,javax,sun等開頭的類。
擴展類加載器
- sun.misc.Launcher$ExtClassLoader實現
- 從JDK安裝目錄的jre/lib/ext子目錄下加載類庫。
- 父類加載器爲null,由於正常狀況下咱們是獲取不到引導類加載器的。
應用程序類加載器
- 也是sun.misc.Launcher類中經過內部類的方式實現。
- 負責classpath指定路徑下的類加載,默認使用此加載器。
注:
1.JVM規範中提到,JVM只支持引導類加載器和自定義類加載器,規範將全部派生於抽象類ClassLoader的類加載器劃分爲自定義類加載器。
2.引導類加載器 -> 擴展類加載器 -> 應用程序類加載器爲上下級關係,並不是繼承關係。
自定義類加載器
爲何要自定義類加載器。
- 隔離加載類。
- 修改類加載的方式。
- 擴展加載源。
- 防止源碼泄露。
怎麼自定義類加載器。
- 繼承ClassLoader類,將自定義的邏輯寫在findClass()方法中。
- 若是沒有特別複雜的需求,可直接繼承URLClassLoader類。
文筆有限,如有錯誤,還望指正,感激涕零。