Java 默认 ClassLoader,只加载指定目录下的 class,如果需要动态加载类到内存,例如 要从远程网络下载的二进制文件类(*.class),然后调用这个类中的方法实现我的业务逻辑,如此,就需要自定义 ClassLoader。
自定义类加载器分为两步:
- 继承 java.lang.ClassLoader
- 重写父类的 findClass() 方法
针对第 1 步,为什么要继承 ClassLoader 这个抽象类,而不继承 AppClassLoader 呢?
因为它和 ExtClassLoader 都是 Launcher 的静态内部类,其访问权限是缺省的包访问权限。
static class AppClassLoader extends URLClassLoader{...}
第 2 步,JDK 的 loadCalss()
方法在所有父类加载器无法加载的时候,会调用本身的 findClass()
方法来进行类加载,因此我们只需重写 findClass()
方法找到类的二进制数据即可。
下面我自定义了一个简单的类加载器,并加载一个简单的类。
首先是需要被加载的简单类:
// 存放于D盘根目录
public class Test {
public static void main(String[] args) {
System.out.println("Test类已成功加载运行!");
ClassLoader classLoader = Test.class.getClassLoader();
System.out.println("加载我的classLoader:" + classLoader);
System.out.println("classLoader.parent:" + classLoader.getParent());
}
}
并使用 javac -encoding utf8 Test.java
编译成 Test.class 文件。
类加载器代码如下:
import java.io.*;
public class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 加载D盘根目录下指定类名的class
String clzDir = "D:\\" + File.separatorChar
+ name.replace('.', File.separatorChar) + ".class";
byte[] classData = getClassData(clzDir);
if (classData == null) {
throw new ClassNotFoundException();
} else {
return defineClass(name, classData, 0, classData.length);
}
}
private byte[] getClassData(String path) {
try (InputStream ins = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream()
) {
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
int bytesNumRead = 0;
while ((bytesNumRead = ins.read(buffer)) != -1) {
baos.write(buffer, 0, bytesNumRead);
}
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
使用类加载器加载调用 Test 类:
public class MyClassLoaderTest {
public static void main(String[] args) throws Exception {
// 指定类加载器加载调用
MyClassLoader classLoader = new MyClassLoader();
classLoader.loadClass("Test").getMethod("test").invoke(null);
}
}
输出信息:
Test.test()已成功加载运行!
加载我的classLoader:class MyClassLoader
classLoader.parent:class sun.misc.Launcher$AppClassLoader
PREVIOUS深入理解Java类加载
NEXT线程上下文类加载器