gpt4 book ai didi

java - 使用 ClassLoader 定义同一个类两次

转载 作者:搜寻专家 更新时间:2023-10-31 20:28:35 24 4
gpt4 key购买 nike

我正在进行一个项目,该项目涉及读取给定 JAR 文件中的所有类,修改这些类中的一些(在字节码级别,使用 ASM ),并创建一个 ClassLoader 这些修改过的类。目前,在修改类之后,我创建了一个 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 的父类(super class),或者类 C 可能实现类 D,或者类 E 可能包含对类 F 的引用,等等 .

对于我的测试,我使用了两个类。第一个名为 fn,第二个名为 fifi 扩展 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 中重新定义类?

最佳答案

我找到了解决问题的方法。基本上,与其覆盖 defineClass 的行为,不如覆盖 findClass。这是有效的代码。

public class ModifiableClassLoader extends ClassLoader {

private final Map<String, byte[]> definitions;

public ModifiableClassLoader(JarFile jar, Map<String, byte[]> definitions) throws MalformedURLException {
super(new URLClassLoader(new URL[] { new URL("jar:" + new File(jar.getName()).toURI().toURL() + "!/") }));
this.definitions = definitions;
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classBytes = definitions.remove(name);
if (classBytes != null) {
return defineClass(name, classBytes, 0, classBytes.length);
}
return super.findClass(name);
}
}

它是根据我现在找不到的另一个 Stack Overflow 问题的答案写的。我以前一定是忽略了它。

关于java - 使用 ClassLoader 定义同一个类两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21507978/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com