破壞雙親委派模型和自定義自己的類載入器
ClassLoader loadeClass原始碼:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
1 . 首先檢查,這個類是否已經被載入過了
2. 沒有被載入過,如果父類載入存在,首先呼叫父類的載入器載入,沒有父類載入使用Bootstrap ClassLoader載入
3. 如果仍然沒有成功載入,呼叫findClass方法(這個方法可以被子類載入器重寫),
從原始碼看出findClass方法是需要開發者自己去實現的,到這裡其實就是呼叫實現的類載入器載入
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
從這裡看出,雙親委派模型的實現依賴於loadClass方法:
1. 如果不想不破壞雙親委派模型,只要去重寫findClass方法
2. 如果想要去破壞雙親委派模型,需要去重寫loadClass方法
自定義類載入器
1. 不破壞雙親委派模型,重寫findClass方法
public class ProtectedClassLoader extends ClassLoader {
public ProtectedClassLoader(ClassLoader parent){
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] by = null;
try {
by = getByteByClassName(name);
return defineClass(name, by, 0, by.length);
} catch (IOException e) {
e.printStackTrace();
}
return super.findClass(name);
}
@Override
public InputStream getResourceAsStream(String name) {
return super.getResourceAsStream(name);
}
private byte[] getByteByClassName(String name) throws IOException {
File file = new File("D:\\MyTest.class");
InputStream is = new FileInputStream(file);
byte[] by = new byte[is.available()];
is.read(by);
is.close();
return by;
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
ClassLoader ml = new ProtectedClassLoader(ClassLoader.getSystemClassLoader().getParent());
Object obj = Class.forName("com.gold.aip.test.MyTest", true, ml).newInstance();
System.out.println(obj);
System.out.println(obj.getClass().getClassLoader());
}
}
輸出結果:
com.gold.aip.test.MyTest@b03be0
com.gold.aip.test.ProtectedClassLoader@14e8cee
測試這段程式碼的過程出現了兩個問題:
1. 如果直接呼叫自定義類載入器的loadClass,結果還是ApplicationClassLoader,改用Class.forName指定載入器去載入
2. Myeclipse環境下,儲存這個類,會自動編譯,結果還是使用ApplicationClassLoader,解決方案:
* 刪除classpath下編譯的class檔案
* 指定類載入器的父類為ExtensionClassLoader,這樣父載入器無法載入,自然給子類載入載入。
* 因為指定了父類載入器,使用getResourceAsStream方法,從原始碼看出是呼叫父類載入器的這個方法,取得的位元組流是空的,
改用FileInputStream直接讀取
2. 破壞雙親載入模型自定義類載入器
package cn.erong.test;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws Exception {
ClassLoader myloader = new ClassLoader() {
@Override
public Class<?> loadClass(String name)
throws ClassNotFoundException {
String fileName = name.substring(name.lastIndexOf(".")+1)+".class";
InputStream is;
try {
is =getClass().getResourceAsStream(fileName);
if(is==null) {return super.loadClass(fileName);}
byte[] by = new byte[is.available()];
is.read(by);
is.close();
return defineClass(name, by, 0, by.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
};
myloader.loadClass("cn.erong.test.Test").newInstance();
}
}
這段程式碼是有問題的,丟擲異常:
java.lang.ClassNotFoundException: Object.class
不過能瞭解到一些東西:
* 測試類Test,繼承Object,因為破壞了雙親載入模型,Object類也會使用這個載入器載入,從Classpath下找這個類,必然會出錯。
* 斷點測試,Object類是後載入的,因為父類永遠比子類先初始化,所以可以看出父類是後載入,但是先解析,初始化
相關文章
- 【JVM】類載入器與雙親委派JVM
- JVM 類載入機制及雙親委派模型JVM模型
- 雙親委派模型與Tomcat類載入架構模型Tomcat架構
- .類載入器及雙親委派機制
- JVM必備基礎知識(二)-- 類載入器和雙親委派模型JVM模型
- 深入理解JVM(③)虛擬機器的類載入器(雙親委派模型)JVM虛擬機模型
- 類檔案的結構、JVM 的類載入過程、類載入機制、類載入器、雙親委派模型JVM模型
- Java類載入機制-雙親委派Java
- 虛擬機器執行子系統_類載入器、雙親委派模型虛擬機模型
- 【JVM第2課】類載入子系統(類載入器、雙親委派)JVM
- 雙親委派模型模型
- JVM之類載入器、載入過程及雙親委派機制JVM
- JVM類載入與雙親委派機制被打破JVM
- JVM面試問題系列:Java類載入機制之雙親委派模型JVM面試Java模型
- 淺談雙親委派模型模型
- 深入探究JVM之類載入與雙親委派機制JVM
- JVM組成以類載入方式(雙親委派機制)、jvm垃圾回收JVM
- JVM類載入機制及雙親委派機制原始碼解讀JVM原始碼
- 面試官:說說雙親委派模型?面試模型
- [JVM]雙親委派JVM
- 自定義類載入器驗證類載入機制
- 類載入流程,類載入機制及自定義類載入器
- Java的類載入器與雙親委託機制Java
- 面試官:雙親委派模型你瞭解嗎?面試模型
- jvm 雙親委派機制JVM
- 【JAVA】自定義類載入器實現類隔離Java
- Java(5)-雙親委派機制Java
- 3_雙親委派機制
- 淺析雙親委派機制
- 從Dubbo核心-SPI聊聊雙親委派機制
- 面試官:如何打破雙親委派機制?面試
- JVM自定義類載入器在程式碼擴充套件性的實踐JVM套件
- pytorch載入語音類自定義資料集PyTorch
- JVM探究(一)談談雙親委派機制和沙箱安全機制JVM
- 探祕類載入器和類載入機制
- Django自定義模型管理器Django模型
- 【JVM進階之路】十四:類載入器和類載入機制JVM
- 虛擬機器類載入機制_類載入時機和類的生命週期虛擬機