【发布时间】:2014-02-02 07:01:11
【问题描述】:
我正在做一个项目,该项目涉及读取给定 JAR 文件中的所有类,修改这些类中的 一些(在字节码级别,使用 ASM),并创建一个 @987654324 @ 这些修改的类。目前,在修改类之后,我创建了 ClassLoader 类的自定义实例,它使 defineMethod(String, byte[]) 可见。
这是自定义ClassLoader的代码(它是一个嵌套类):
private static class ExposingClassLoader extends ClassLoader {
private ExposingClassLoader(JarFile jar) throws MalformedURLException {
super(new URLClassLoader(new URL[] { new URL("jar:" + new File(jar.getName()).toURI().toURL() + "!/") }));
}
private void defineClass(String name, byte[] data) {
defineClass(name, data, 0, data.length);
}
}
您可能已经注意到我将父类加载器设为URLClassLoader。当我构建自定义类加载器时,我让URLClassLoader 引用包含未修改类文件的 JAR。在修改了一些类文件后,我遍历它们并为每个类调用defineMethod(String, byte[])。一些修改后的类相互依赖,即类 A 可能是类 B 的超类,或者类 C 可能实现类 D,或者类 E 可能包含对类 F 的引用,等等 .
对于我的测试,我使用了两个类。第一个名为fn,第二个名为fi,fi 扩展fn 并包含多个fi 类型的字段。这两个类都存在于用于构造ClassLoader 的JAR 文件中,唯一的区别是它们没有被修改。出于某种原因,如果我定义类fn 它工作正常(它不应该?类fn 已经存在于JAR 文件中)。但是,如果我尝试定义fi,它又多次引用fn,我会得到这个异常:
Exception in thread "main" java.lang.LinkageError: loader (instance of Injector$ExposingClassLoader): attempted duplicate class definition for name: "fn"
上线:
defineClass(name, data, 0, data.length);
我不知道如何处理这个问题。最简单的方法是“卸载”包含在 JAR 中的类,但仅限于我修改过的类。这样,当我定义修改后的类时,它们将不会被加载到 ClassLoader 中。但是,我环顾四周,还没有找到一种干净的方法来做到这一点。有人说我需要单独的(多个)类加载器,这对我的项目不起作用,除非有一种方法可以将这些多个类加载器组合成一个,比如包装器。
如何在ClassLoader 中重新定义一个类?
【问题讨论】:
标签: java classloader