超詳細java中的ClassLoader詳解
本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出
ClassLoader翻譯過來就是類載入器,普通的Java開發者其實用到的不多,但對於某些框架開發者來說卻非常常見。理解ClassLoader的載入機制,也有利於我們編寫出更高效的程式碼。ClassLoader的具體作用就是將class檔案載入到jvm虛擬機器中去,程式就可以正確運行了。但是,jvm啟動的時候,並不會一次性載入所有的class檔案,而是根據需要去動態載入。想想也是的,一次性載入那麼多jar包那麼多class,那記憶體不崩潰。本文的目的也是學習ClassLoader這種載入機制。
備註:本文篇幅比較長,但內容簡單,大家不要恐慌,安靜地耐心翻閱就是
Class檔案的認識
我們都知道在Java中程式是執行在虛擬機器中,我們平常用文字編輯器或者是IDE編寫的程式都是.java格式的檔案,這是最基礎的原始碼,但這類檔案是不能直接執行的。如我們編寫一個簡單的程式HelloWorld.java
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
如圖:
然後,我們需要在命令列中進行java檔案的編譯
- 1
- 1
可以看到目錄下生成了.class檔案
我們再從命令列中執行命令:
- 1
- 1
上面是基本程式碼示例,是所有入門JAVA語言時都學過的東西,這裡重新拿出來是想讓大家將焦點回到class檔案上,class檔案是位元組碼格式檔案,java虛擬機器並不能直接識別我們平常編寫的.java原始檔,所以需要javac這個命令轉換成.class檔案。另外,如果用C或者Python編寫的程式正確轉換成.class檔案後,java虛擬機器也是可以識別執行的。更多資訊大家可以參考這篇。
瞭解了.class檔案後,我們再來思考下,我們平常在Eclipse中編寫的java程式是如何執行的,也就是我們自己編寫的各種類是如何被載入到jvm(java虛擬機器)中去的。
你還記得java環境變數嗎?
初學java的時候,最害怕的就是下載JDK後要配置環境變量了,關鍵是當時不理解,所以戰戰兢兢地照著書籍上或者是網路上的介紹進行操作。然後下次再弄的時候,又忘記了而且是必忘。當時,心裡的想法很氣憤的,想著是–這東西一點也不人性化,為什麼非要自己配置環境變數呢?太不照顧菜鳥和新手了,很多菜鳥就是因為卡在環境變數的配置上,遭受了太多的挫敗感。
因為我是在Windows下程式設計的,所以只講Window平臺上的環境變數,主要有3個:JAVA_HOME、PATH、CLASSPATH。
JAVA_HOME
指的是你JDK安裝的位置,一般預設安裝在C盤,如
- 1
- 1
PATH
將程式路徑包含在PATH當中後,在命令列視窗就可以直接鍵入它的名字了,而不再需要鍵入它的全路徑,比如上面程式碼中我用的到javac
和java
兩個命令。
一般的
- 1
- 1
也就是在原來的PATH路徑上新增JDK目錄下的bin目錄和jre目錄的bin.
CLASSPATH
- 1
- 1
一看就是指向jar包路徑。
需要注意的是前面的.;
,.
代表當前目錄。
環境變數的設定與檢視
設定可以右擊我的電腦,然後點選屬性,再點選高階,然後點選環境變數,具體不明白的自行查閱文件。
檢視的話可以開啟命令列視窗
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
好了,扯遠了,知道了環境變數,特別是CLASSPATH時,我們進入今天的主題Classloader.
JAVA類載入流程
Java語言系統自帶有三個類載入器:
- Bootstrap ClassLoader 最頂層的載入類,主要載入核心類庫,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。另外需要注意的是可以通過啟動jvm時指定-Xbootclasspath和路徑來改變Bootstrap ClassLoader的載入目錄。比如java
-Xbootclasspath/a:path
被指定的檔案追加到預設的bootstrap路徑中。我們可以開啟我的電腦,在上面的目錄下檢視,看看這些jar包是不是存在於這個目錄。
- Extention ClassLoader 擴充套件的類載入器,載入目錄%JRE_HOME%\lib\ext目錄下的jar包和class檔案。還可以載入-D java.ext.dirs
選項指定的目錄。
- Appclass Loader也稱為SystemAppClass 載入當前應用的classpath的所有類。
我們上面簡單介紹了3個ClassLoader。說明了它們載入的路徑。並且還提到了-Xbootclasspath
和-D
java.ext.dirs
這兩個虛擬機器引數選項。
載入順序?
我們看到了系統的3個類載入器,但我們可能不知道具體哪個先行呢?
我可以先告訴你答案
1. Bootstrap CLassloder
2. Extention ClassLoader
3. AppClassLoader
為了更好的理解,我們可以檢視原始碼。
看sun.misc.Launcher,它是一個java虛擬機器的入口應用。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
原始碼有精簡,我們可以得到相關的資訊。
1. Launcher初始化了ExtClassLoader和AppClassLoader。
2. Launcher中並沒有看見BootstrapClassLoader,但通過System.getProperty("sun.boot.class.path")
得到了字串bootClassPath
,這個應該就是BootstrapClassLoader載入的jar包路徑。
我們可以先程式碼測試一下sun.boot.class.path
是什麼內容。
- 1
- 1
得到的結果是:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
可以看到,這些全是JRE目錄下的jar包或者是class檔案。
ExtClassLoader原始碼
如果你有足夠的好奇心,你應該會對它的原始碼感興趣
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
我們先前的內容有說過,可以指定-D java.ext.dirs
引數來新增和改變ExtClassLoader的載入路徑。這裡我們通過可以編寫測試程式碼。