Java classloader類加載器的實(shí)現(xiàn)
Classloader的繼承性。
第一級(jí)叫做bootstrap classloader,加載JDK自帶的類,也就是${JAVA_HOME}/lib下的類。
第二級(jí)叫做extern classloader,加載${JAVA_HOME}/lib/ext下的類。
第三級(jí)叫做system classloader,加載第三方的類,就是classpath里其他的類。
第四級(jí)及更高級(jí)叫做plugin classloader,是用戶自己寫的classloader或者new出來的URLClassLoader,加載classpath以外的類。在tomcat容器中,每個(gè)應(yīng)用里的WEB-INF/lib和WEB-INF/classes就是通過tomcat自定義的classloader去加載的。
Classloader的隔離性。
- 父級(jí)不能調(diào)用子級(jí)的類。
比如extern classloader里加載的class不能調(diào)用system classloader加載的類,會(huì)拋class not found異常. - 同一級(jí)不同classloader加載的類不能互相調(diào)用。
比如有兩個(gè)plugin classloader, loader A 與loader B。loader A加載的類class A不能調(diào)用loader B加載的類 class B. - 無法獲取bootstrap Classloader的實(shí)例。
System.out.println(String.class.getClassLoader());
這個(gè)輸出結(jié)果是null
總而言之,只能child加載的類調(diào)用parent加載的類。兄弟及各種遠(yuǎn)房親戚不能互相調(diào)用。
簡單的plugin classloader
直接使用jdk自帶的url classloader就可以加載任意jar包里的類了。
比如以下代碼
final URL url = new URL("file:///C:/Users/Ryan/IdeaProjects/learn/classloader/heap-1.0.jar");
final URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
final Class<?> heapClass = classLoader.loadClass("net.cloudsun.head.SmallHeap");
final Constructor<?> constructor = heapClass.getConstructor();
final Object o = constructor.newInstance();
final Method add = heapClass.getMethod("add", java.lang.Comparable.class);
for (int i = 0; i < 10; i++) {
add.invoke(o, -i);
}
System.out.println(o);
自定義classloader
當(dāng)不能提供url時(shí),比如jar包不在磁盤里,也不在http服務(wù)器上,或者jar包是加密的。只能自己寫classloader進(jìn)行類的加載。
自己寫classloader最終必須繼承Classloader類。因?yàn)檫@個(gè)類有個(gè)保護(hù)型且final的defineClass方法,傳入類的字節(jié)碼,也就是byte[],就可以加載一個(gè)類。也就是說class的來源是byte[]。
比如
public class JarClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
// 從jar包里取byte數(shù)組
try {
JarFile jarFile = new JarFile("heap-1.0.jar");
final byte[] bytes = JarUtils.getByte(jarFile, name);
if (bytes == null) {
return super.loadClass(name);
}
return super.defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
上述代碼的JarUtils是一個(gè)自己寫的工具類。
public static byte[] getByte(JarFile jarFile, String className) {
final String entry = className.replace('.', '/') + ".class";
final JarEntry jarEntry = jarFile.getJarEntry(entry);
if (jarEntry == null) {
return null;
}
try (final InputStream inputStream = jarFile.getInputStream(jarEntry)) {
return IOUtils.toByteArray(inputStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
當(dāng)然這個(gè)classloader寫得并不規(guī)范。因?yàn)橐?guī)范的classloader首先要調(diào)用parent classloader去加載類,如果parent加載失敗,再自己加載,而且加載的class必須緩存起來。因?yàn)閺淖止?jié)碼加載class的開銷是非常巨大的。當(dāng)然前三級(jí)JDK自帶的的classloader都會(huì)在loadClass方法里去檢查class是否已經(jīng)加載。所以只要每級(jí)class loader優(yōu)先調(diào)用parent classloader,就可以自動(dòng)實(shí)現(xiàn)class的緩存。
到此這篇關(guān)于Java classloader類加載器的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java classloader內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java微信小程序oss圖片上傳的實(shí)現(xiàn)方法
這篇文章主要介紹了Java微信小程序oss圖片上傳的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
SpringBoot打印詳細(xì)啟動(dòng)異常信息
這篇文章主要介紹了SpringBoot打印詳細(xì)啟動(dòng)異常信息,本文包含了詳細(xì)的過程解析與案例,概要的說明了如何去使用打印啟動(dòng)異常信息,需要的朋友可以參考下2021-06-06
java與JSON數(shù)據(jù)的轉(zhuǎn)換實(shí)例詳解
這篇文章主要介紹了java與JSON數(shù)據(jù)的轉(zhuǎn)換實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03

