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

时间:2019-07-03 21:25:44

标签: java byte-buddy

我试图在运行时用新版本重新定义代码中的现有类(称为模块)。新版本以已编译的类文件的形式保存在某些目录中。我可以用ByteBuddy做到这一点吗?

我尝试使用ByteArrayClassLoader从类文件中定义一个类。定义的类似乎具有更新的方法。我已经通过检查定义的类的方法并调用它们(即process方法,该方法返回一些String)来进行检查。但是,当我尝试使用ByteBuddy.redefine(...)时,出现错误“无法为some.package.Module找到类文件”,我尝试传入用于查找新版本的类文件的ClassFileLocator但我仍然收到此错误。

    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

重新定义失败,当前代码失败

1 个答案:

答案 0 :(得分:0)

如果您只是想用另一个字节码表示形式替换另一个类,为什么要使用字节伙伴?

您可以使用InstrumentationredefineClass API替换类,在其中您可以直接传递替换内容。

该错误可能是由于您使用REDEFINE策略所致,其中Byte Buddy需要定位所有类的类文件。使用RETRANSFORM可能会更好。但是,没有堆栈跟踪就无法确定。