如何从已编译的类文件中重新定义已加载的 类

How to redefine loaded classes from compiled classfiles

我正在尝试在运行时使用新版本重新定义代码中现有的 class(称为模块)。新版本以编译后的 class 文件的形式出现,这些文件保存在某个目录中。我有办法用 ByteBuddy 做到这一点吗?

我尝试使用 ByteArrayClassLoader 从 class 文件中定义一个 class。定义的 class 似乎有更新的方法。我已经通过定义的 class 的方法并调用它们(即 returns 一些字符串的 process 方法)检查​​了这一点。但是,当我尝试使用 ByteBuddy.redefine(...) 时,出现错误 "Could not locate class file for some.package.Module" 我尝试传入 ClassFileLocator 用于查找新版本的 class 文件,但我仍然出现此错误。

    public void redefine() throws Exception {

        String path = System.getProperty("user.dir")+"/someDir";

        Map<String, byte[]> map = new HashMap<>();
        ClassFileLocator cfl = new ForFolder(new File(path));
        byte[] clazzBytes = cfl.locate("Module").resolve();
        map.put(clazz.getName(), clazzBytes);

        ByteArrayClassLoader bac = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, false, map);

        Class<?> replacementClass = bac.defineClass(clazz.getName(), clazzBytes);

        for (Method m : replacementClass.getMethods()) {
            if (m.getName().equals("process")) {
                System.out.println((String) m.invoke(replacementClass.newInstance(), "invoked from new instance"));
            }
        }
        AgentBuilder agentBuilder = new AgentBuilder.Default()
            .with(new Listener.Filtering(
                new StringMatcher("bytebuddy_instrumentation.Module", Mode.CONTAINS),
                Listener.StreamWriting.toSystemOut()
            ))
            .with(RedefinitionStrategy.REDEFINITION)
            .with(Default.REDEFINE)
            .disableClassFormatChanges()
            .type(ElementMatchers.is(clazz))
            .transform((builder, typeDescription, classLoader, module) ->
                new ByteBuddy()
                    .redefine(replacementClass, cfl)
                    .name(clazz.getName()));

        this.resetter = agentBuilder.installOnByteBuddyAgent();
    }

由于java.lang.IllegalStateException: Could not locate class file for some.package.Module

,当前代码重新定义失败

如果您只是想用另一种字节码表示替换另一个 class,为什么要使用 Byte Buddy?

您可以使用 redefineClass 将 class 替换为 Instrumentation API,您可以直接通过替换。

错误可能源于您使用了 REDEFINE 策略,其中 Byte Buddy 需要找到所有 class 的 class 文件。使用 RETRANSFORM 可能会更好。但是,如果没有堆栈跟踪就无法确定。