重写 loadclass 方法的核心在于继承 classloader 并重写其核心逻辑,通常建议保留双亲委派机制的调用链,仅在特定条件下拦截类加载请求。具体做法是创建一个自定义类加载器,在 loadclass(string name, boolean resolve) 方法中先检查是否满足自定义条件(如类名前缀),若满足则通过 findclass 获取字节码并返回,否则委托给父加载器处理。

如何构建支持指定前缀拦截的自定义类加载器
要实现一个能识别特定命名空间(例如 com.custom.)的类加载器,需要定义一个继承自 java.lang.ClassLoader 的类。在该类中,必须实现 findClass 方法来提供具体的字节码数据,而 loadClass 方法负责控制加载流程。标准的做法是在 loadClass 中先判断目标类名是否符合拦截规则,如果符合,则调用 findClass;如果不符,则递归调用 super.loadClass(name, resolve) 以维持双亲委派模型。
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class CustomClassLoader extends ClassLoader {
private String classPath;
public CustomClassLoader(String classPath) {
this.classPath = classPath;
}
@Override
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// 1. 检查是否已加载
Class> c = findLoadedClass(name);
if (c != null) {
if (resolve) resolveClass(c);
return c;
}
// 2. 判断是否由当前加载器加载
if (name.startsWith("com.custom.")) {
try {
byte[] data = loadData(name);
c = defineClass(name, data, 0, data.length);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
if (resolve) resolveClass(c);
return c;
}
// 3. 委托给父加载器
return super.loadClass(name, resolve);
}
private byte[] loadData(String name) throws IOException {
String path = name.replace('.', '/') + ".class";
try (FileInputStream fis = new FileInputStream(classPath + path);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
}
}
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











