自定義ClassLoader的實現
- 2019 年 12 月 5 日
- 筆記
ClassLoader 是 JVM 結構中很重要的一塊,也可以說是整個 JVM 運行機制的入口,程式通過 ClassLoader 將編譯好的位元組碼文件載入到記憶體中,生成 Class,進而創建對象,之後才能進行各種運算、解析,最終生成機器碼提交到作業系統中。
JVM 結構如下圖所示。

ClassLoader 有 4 種具體的分類:
1、BootstrapClassLoader
2、ExtClassLoader
3、AppClassLoader
4、自定義 ClassLoader
BootstrapClassLoader 用來載入 Java 的核心類庫,即存放在 java.* 包中的位元組碼文件,如 java.util.List、java.io.InputStream、java.lang.Integer 等。
ExtClassLoader 用來載入 Java 的擴展類庫,即存放在 javax.* 包中的位元組碼文件,如 javax.sql.DataSource、javax.net.SocketFactory 等。
AppClassLoader 用來載入當前程式所在目錄的類,即開發者自己編寫的 Java 文件對應的位元組碼文件。
自定義的 ClassLoader 指開發者根據具體需求編寫的類載入器,可以實現訂製化載入。
接下來我們來實現一個自定義的 ClassLoader,首先是準備工作,ClassLoader 的作用是將位元組碼文件載入到記憶體中,所有你得先有位元組碼文件。
1、創建一個 Java 文件。
public class HelloWorld{ public HelloWorld(){ System.out.println("創建了HelloWorld對象"); } }
2、將其編譯成位元組碼文件。
javac HelloWorld.java
有了位元組碼文件,接下來就可以編寫自定義 ClassLoader,並通過其載入位元組碼文件了,ClassLoader 具體的工作流程主要是通過兩個方法完成類載入的,分別是 findClass 和 defineClass。
findClass 根據路徑載入位元組碼文件,然後交給 defineClass,再把位元組碼轉化為 Class。自定義 ClassLoader 需要開發者對 findClass 方法進行重寫,完成載入位元組碼文件的操作,之後再將位元組數據傳給 ClassLoader 的 defineClass 方法即可,根據這個思路,我們來實現程式碼。
3、創建自定義 ClassLoader,並繼承 ClassLoader。
import java.io.*; public class MyClassLoader extends ClassLoader { private String path; public MyClassLoader(String path) { this.path = path; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String classPath = path+name+".class"; InputStream inputStream = null; ByteArrayOutputStream outputStream = null; try { inputStream = new FileInputStream(classPath); outputStream = new ByteArrayOutputStream(); int temp = 0; while((temp = inputStream.read()) != -1){ outputStream.write(temp); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { outputStream.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } byte[] bytes = outputStream.toByteArray(); return defineClass(name,bytes,0,bytes.length); } }
在 findClass 方法中,我們通過 IO 流讀取本地編譯好的位元組碼文件,生成位元組數組,再將位元組數組傳給 ClassLoader 的 defineClass 方法即可。
4、進行測試,實例化 MyClassLoader,並通過該實例化對象載入位元組碼文件獲取 Class 對象。
public class Test { public static void main(String[] args) { MyClassLoader myClassLoader = new MyClassLoader("/Users/southwind/myjava/"); try { Class clazz = myClassLoader.findClass("HelloWorld"); System.out.println(clazz); System.out.println(clazz.getConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } } }
5、運行結果如下圖所示。

HelloWorld 位元組碼文件載入成功,以上就是自定義 ClassLoader 的用法,你學會了嗎?