ClassLoader在Java中有著非常重要的作用,主要工作在Class裝載的加載階段,其主要作用是從系統(tǒng)外部獲得Class二進制數(shù)據(jù)流。它是Java的核心組件,所有的Class都是由ClassLoader進行加載的,ClassLoader負責將Class里的二進制數(shù)據(jù)流裝載進系統(tǒng),然后交給Java虛擬機進行連接,初始化等操作。
在加載階段,虛擬機需要完成以下三件事:
- 通過類的全限名獲取此類的二進制字節(jié)流。
- 將這個字節(jié)流所代表的靜態(tài)存儲結構轉換為方法區(qū)的運行時數(shù)據(jù)區(qū)
- 在內存中生成一個代表這個類的Class對象,作為方法區(qū)的這個類的各種數(shù)據(jù)訪問入口。
那么如何自定義ClassLoader呢?
其實只需要重寫findClass即可,findClass在找到Class對象后,調用defineClass來定義Class字節(jié)流。
代碼
- 先新建一個Java文件,在系統(tǒng)上的位置,然后用javac編譯java文件。
//編譯
//javac src/test/java/me/aihe/demo/Hello.java
public class Hello {
static {
System.out.println("hello");
}
}
- 新建ClassLoader,重寫findClass方法。
public class MyClassLoader extends ClassLoader {
private String path;
private String classLoaderName;
public MyClassLoader(String path, String classLoaderName) {
this.path = path;
this.classLoaderName = classLoaderName;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private byte[] loadClassData(String name) throws IOException {
name = path + name + ".class";
InputStream is = null;
ByteArrayOutputStream outputStream = null;
try {
is = new FileInputStream(new File(name));
outputStream = new ByteArrayOutputStream();
int i = 0;
while ((i = is.read()) != -1) {
outputStream.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.close();
}
if (is != null) {
is.close();
}
}
return outputStream.toByteArray();
}
}
- 新建測試類,看看剛才寫的ClassLoader是否生效。
public class ClassLoaderChecker {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader myClassLoader = new MyClassLoader("/Users/aihe/Desktop/extra/spring-boot-learn/src/test/java/me/aihe/demo/", "random");
Class c = myClassLoader.loadClass("Hello");
System.out.println("ClassLoader:" + c.getClassLoader());
Object instance = c.newInstance();
}
}
-
運行查看結果,可以看到盡管Class文件是被我們自己的ClassLoader加載的,并且Class對象可以用來新建Java對象。
image.png
最后
自定義類加載器有很多好處,它讓Java代碼更加靈活,應用場景:
- 可以用來加密Class文件,然后解密Class文件進行再加載,提高系統(tǒng)安全性
- 從網(wǎng)絡中加載Class文件
