JavaClass Loader的工作原理在宮力等人的《Inside Java 2 Platform Security》和BillVenners的《Inside Java 2 VirturlMachine》里面有非常精彩的介紹。不過這個(gè)問題還是困惑了我一段時(shí)間,所以把心得小結(jié)如下。
JVM采用動(dòng)態(tài)類型加載方式,所以概念上只有當(dāng)一個(gè)類型被應(yīng)用到時(shí),虛擬機(jī)才會(huì)加載它。比如,假設(shè)類C引用了類D,只有當(dāng)虛擬機(jī)執(zhí)行到C中引用D的語句時(shí)才會(huì)去加載D。
Defining class loader是指真正執(zhí)行加載某個(gè)類的動(dòng)作的那個(gè)類加載器實(shí)例。在虛擬機(jī)中,一個(gè)類型C是由其類型名和定義它的那個(gè)defining class loader來唯一標(biāo)識(shí)的,即C=<N, L>。Iniating class loader是指發(fā)起這個(gè)加載動(dòng)作的類加載器實(shí)例。比如在前面的例子中,虛擬機(jī)發(fā)現(xiàn)C引用D時(shí),就把C的defining class loader作為D的initiating class loader。至于D最終是由誰定義的,則要由class loader的代理機(jī)制來決定。
文章和書籍中常常提到下面幾種class loader:
Class loader之間有兩種層次關(guān)系:繼承關(guān)系和代理(delegation)關(guān)系。
除bootstrap class loader之外的所有其它c(diǎn)lassloader都是用Java語言來實(shí)現(xiàn)的,所以它們之間自然有繼承關(guān)系。JavaAPI里面定義的類的繼承關(guān)系如下:java.net.URLClassLoader -->java.security.SecureClassLoader --> java.lang.ClassLoader -->java.lang.Object。
代理關(guān)系是classloader實(shí)例之間的動(dòng)態(tài)關(guān)系。在創(chuàng)建一個(gè)classloader實(shí)例時(shí)可以給其構(gòu)造函數(shù)傳遞一個(gè)parent參數(shù),這樣該parent就成了新創(chuàng)建的classloader在代理層次上的父節(jié)點(diǎn)。這個(gè)層次樹的根節(jié)點(diǎn)就是bootstrap class loader實(shí)例。Java程序可以通過調(diào)用classloader實(shí)例的getParent()方法來獲取其父節(jié)點(diǎn)。比如在JDK1.5中運(yùn)行HelloWorld程序時(shí)classloader的代理繼承關(guān)系如下:sun.misc.Launcher$AppClassLoader -->sun.misc.Launcher$ExtClassLoader --> null (bootstrap class loader)。
當(dāng)一個(gè)class loader收到加載某個(gè)類的請求時(shí),它按照下面的流程處理:
所以在代理層次結(jié)構(gòu)上的子節(jié)點(diǎn)永遠(yuǎn)只加載父節(jié)點(diǎn)(及其祖先節(jié)點(diǎn))所不能加載的類,這樣可以保證類始終被合適的class loader加載,比如rt.jar中的類永遠(yuǎn)被bootstrap class loader加載。
回到HelloWorld的例子。當(dāng)虛擬機(jī)一開始加載HelloWorld類的時(shí)候,它的initiating classloader是application class loader,該類調(diào)用extension classloader,它又調(diào)用bootstrap class loader;bootstrap classloader(在rt.jar中)找不到HelloWorld類,拋出異常;extension classloader截獲異常后開始試圖自己加載,但是它(在擴(kuò)展包內(nèi))也找不到HelloWorld,于是也拋出異常;application classloader截獲這個(gè)異常,它在CLASSPATH中找到了HelloWorld于是加載并定義了這個(gè)類,所以HelloWorld類的definingclass loader就是這個(gè)application class loader實(shí)例。
當(dāng)HelloWorld引用到j(luò)ava.lang.System類時(shí)虛擬機(jī)開始加載System類。這時(shí)定義了HelloWorld類的application class loader就成了System類的iniating classloader。重復(fù)上述操作,但是這次bootstrap class loader找到了System類就定義了該類,后面的extensionclass loader和application classloader就不再試圖加載了。所以java.lang.System類的defining class loader就是bootstrapclass loader。
聯(lián)系客服