日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Ken Wu's Blog ? java類(lèi)加載器體系結(jié)構(gòu)(含hotswap原理)

 hero jack 2011-02-16

java類(lèi)加載器體系結(jié)構(gòu)(含hotswap原理)

jvm classLoader architecture :

a, Bootstrap ClassLoader/啟動(dòng)類(lèi)加載器
主要負(fù)責(zé)jdk_home/lib目錄下的核心 api 或 -Xbootclasspath 選項(xiàng)指定的jar包裝入工作.

b, Extension ClassLoader/擴(kuò)展類(lèi)加載器
主要負(fù)責(zé)jdk_home/lib/ext目錄下的jar包或 -Djava.ext.dirs 指定目錄下的jar包裝入工作

c, System ClassLoader/系統(tǒng)類(lèi)加載器
主要負(fù)責(zé)java -classpath/-Djava.class.path所指的目錄下的類(lèi)與jar包裝入工作.

b, User Custom ClassLoader/用戶自定義類(lèi)加載器(java.lang.ClassLoader的子類(lèi))
在程序運(yùn)行期間, 通過(guò)java.lang.ClassLoader的子類(lèi)動(dòng)態(tài)加載class文件, 體現(xiàn)java動(dòng)態(tài)實(shí)時(shí)類(lèi)裝入特性.

類(lèi)加載器的特性:

1, 每個(gè)ClassLoader都維護(hù)了一份自己的名稱空間, 同一個(gè)名稱空間里不能出現(xiàn)兩個(gè)同名的類(lèi)。
2, 為了實(shí)現(xiàn)java安全沙箱模型頂層的類(lèi)加載器安全機(jī)制, java默認(rèn)采用了 ” 雙親委派的加載鏈 ” 結(jié)構(gòu).
如下圖:
java class loader

Class Diagram:
classloader 類(lèi)圖

類(lèi)圖中, BootstrapClassLoader是一個(gè)單獨(dú)的java類(lèi), 其實(shí)在這里, 不應(yīng)該叫他是一個(gè)java類(lèi)。
因?yàn)椋?它已經(jīng)完全不用java實(shí)現(xiàn)了。

它是在jvm啟動(dòng)時(shí), 就被構(gòu)造起來(lái)的, 負(fù)責(zé)java平臺(tái)核心庫(kù)。(具體上面已經(jīng)有介紹)

啟動(dòng)類(lèi)加載實(shí)現(xiàn) (其實(shí)我們不用關(guān)心這塊, 但是有興趣的, 可以研究一下 ):
bootstrap classLoader 類(lèi)加載原理探索

自定義類(lèi)加載器加載一個(gè)類(lèi)的步驟 :

自定義類(lèi)加載器加載一個(gè)類(lèi)的步驟

ClassLoader 類(lèi)加載邏輯分析, 以下邏輯是除 BootstrapClassLoader 外的類(lèi)加載器加載流程:

// 檢查類(lèi)是否已被裝載過(guò)
Class c = findLoadedClass(name);
if (c == null ) {
// 指定類(lèi)未被裝載過(guò)
try {
if (parent != null ) {
// 如果父類(lèi)加載器不為空, 則委派給父類(lèi)加載
c = parent.loadClass(name, false );
} else {
// 如果父類(lèi)加載器為空, 則委派給啟動(dòng)類(lèi)加載加載
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
// 啟動(dòng)類(lèi)加載器或父類(lèi)加載器拋出異常后, 當(dāng)前類(lèi)加載器將其
// 捕獲, 并通過(guò)findClass方法, 由自身加載
c = findClass(name);
}
}

用Class.forName加載類(lèi)
Class.forName使用的是被調(diào)用者的類(lèi)加載器來(lái)加載類(lèi)的.
這種特性, 證明了java類(lèi)加載器中的名稱空間是唯一的, 不會(huì)相互干擾.
即在一般情況下, 保證同一個(gè)類(lèi)中所關(guān)聯(lián)的其他類(lèi)都是由當(dāng)前類(lèi)的類(lèi)加載器所加載的.

public static Class forName(String className)
throws ClassNotFoundException {
return forName0(className, true , ClassLoader.getCallerClassLoader());
}
 
/** Called after security checks have been made. */
private static native Class forName0(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException;

上圖中 ClassLoader.getCallerClassLoader 就是得到調(diào)用當(dāng)前forName方法的類(lèi)的類(lèi)加載器

線程上下文類(lèi)加載器
java默認(rèn)的線程上下文類(lèi)加載器是 系統(tǒng)類(lèi)加載器(AppClassLoader).

// Now create the class loader to use to launch the application
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader" );
}
 
// Also set the context class loader for the primordial thread.
Thread.currentThread().setContextClassLoader(loader);

以上代碼摘自sun.misc.Launch的無(wú)參構(gòu)造函數(shù)Launch()。
使用線程上下文類(lèi)加載器, 可以在執(zhí)行線程中, 拋棄雙親委派加載鏈模式, 使用線程上下文里的類(lèi)加載器加載類(lèi).
典型的例子有, 通過(guò)線程上下文來(lái)加載第三方庫(kù)jndi實(shí)現(xiàn), 而不依賴于雙親委派.
大部分java app服務(wù)器(jboss, tomcat..)也是采用contextClassLoader來(lái)處理web服務(wù)。
還有一些采用 hotswap 特性的框架, 也使用了線程上下文類(lèi)加載器, 比如 seasar (full stack framework in japenese).

線程上下文從根本解決了一般應(yīng)用不能違背雙親委派模式的問(wèn)題.
使java類(lèi)加載體系顯得更靈活.

隨著多核時(shí)代的來(lái)臨, 相信多線程開(kāi)發(fā)將會(huì)越來(lái)越多地進(jìn)入程序員的實(shí)際編碼過(guò)程中. 因此,
在編寫(xiě)基礎(chǔ)設(shè)施時(shí), 通過(guò)使用線程上下文來(lái)加載類(lèi), 應(yīng)該是一個(gè)很好的選擇.

當(dāng)然, 好東西都有利弊. 使用線程上下文加載類(lèi), 也要注意, 保證多根需要通信的線程間的類(lèi)加載器應(yīng)該是同一個(gè),
防止因?yàn)椴煌念?lèi)加載器, 導(dǎo)致類(lèi)型轉(zhuǎn)換異常(ClassCastException).

自定義的類(lèi)加載器實(shí)現(xiàn)
defineClass(String name, byte[] b, int off, int len,ProtectionDomain protectionDomain)
是java.lang.Classloader提供給開(kāi)發(fā)人員, 用來(lái)自定義加載class的接口.

使用該接口, 可以動(dòng)態(tài)的加載class文件.

例如,
在jdk中, URLClassLoader是配合findClass方法來(lái)使用defineClass, 可以從網(wǎng)絡(luò)或硬盤(pán)上加載class.

而使用類(lèi)加載接口, 并加上自己的實(shí)現(xiàn)邏輯, 還可以定制出更多的高級(jí)特性.

比如,

一個(gè)簡(jiǎn)單的hot swap 類(lèi)加載器實(shí)現(xiàn):

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
 
/**
* 可以重新載入同名類(lèi)的類(lèi)加載器實(shí)現(xiàn)
*
 
* 放棄了雙親委派的加載鏈模式.
* 需要外部維護(hù)重載后的類(lèi)的成員變量狀態(tài).
*
* @author ken.wu
* @mail ken.wug@gmail.com
* 2007-9-28 下午01:37:43
*/
public class HotSwapClassLoader extends URLClassLoader {
 
public HotSwapClassLoader(URL[] urls) {
super (urls);
}
 
public HotSwapClassLoader(URL[] urls, ClassLoader parent) {
super (urls, parent);
}
 
public Class load(String name)
throws ClassNotFoundException {
return load(name, false );
}
 
public Class load(String name, boolean resolve)
throws ClassNotFoundException {
if ( null != super .findLoadedClass(name))
return reload(name, resolve);
 
Class clazz = super .findClass(name);
 
if (resolve)
super .resolveClass(clazz);
 
return clazz;
}
 
public Class reload(String name, boolean resolve)
throws ClassNotFoundException {
return new HotSwapClassLoader( super .getURLs(), super .getParent()).load(
name, resolve);
}
}
 
public class A {
private B b;
 
public void setB(B b) {
this .b = b;
}
 
public B getB() {
return b;
}
}
 
public class B {}

這個(gè)類(lèi)的作用是可以重新載入同名的類(lèi), 但是, 為了實(shí)現(xiàn)hotswap, 老的對(duì)象狀態(tài)
需要通過(guò)其他方式拷貝到重載過(guò)的類(lèi)生成的全新實(shí)例中來(lái)。(A類(lèi)中的b實(shí)例)

而新實(shí)例所依賴的B類(lèi)如果與老對(duì)象不是同一個(gè)類(lèi)加載器加載的, 將會(huì)拋出類(lèi)型轉(zhuǎn)換異常(ClassCastException).

為了解決這種問(wèn)題, HotSwapClassLoader自定義了load方法. 即當(dāng)前類(lèi)是由自身classLoader加載的, 而內(nèi)部依賴的類(lèi)還是老對(duì)象的classLoader加載的.

public class TestHotSwap {
public static void main(String args[]) {
A a = new A();
B b = new B();
a.setB(b);
 
System.out.printf("A classLoader is %s n" , a.getClass().getClassLoader());
System.out.printf("B classLoader is %s n" , b.getClass().getClassLoader());
System.out.printf("A.b classLoader is %s n" ,   a.getB().getClass().getClassLoader());
 
HotSwapClassLoader c1 = new HotSwapClassLoader( new URL[]{ new URL( "file:\e:\test\")} , a.getClass().getClassLoader());
Class clazz = c1.load(" test.hotswap.A ");
Object aInstance = clazz.newInstance();
 
Method method1 = clazz.getMethod(" setB ", B.class);
method1.invoke(aInstance, b);
 
Method method2 = clazz.getMethod(" getB ", null);
Object bInstance = method2.invoke(aInstance, null);
 
System.out.printf(" reloaded A.b classLoader is %s n", bInstance.getClass().getClassLoader());
}
}

輸出

A classLoader is sun.misc.Launcher$AppClassLoader@19821f
B classLoader is sun.misc.Launcher$AppClassLoader@19821f
A.b classLoader is sun.misc.Launcher$AppClassLoader@19821f
reloaded A.b classLoader is sun.misc.Launcher$AppClassLoader@19821f

轉(zhuǎn)載請(qǐng)注明原文鏈接:http:///structure-of-java-class-loader

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多