如何从已编译的类文件中重新定义已加载的 类
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
可能会更好。但是,如果没有堆栈跟踪就无法确定。
我正在尝试在运行时使用新版本重新定义代码中现有的 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
可能会更好。但是,如果没有堆栈跟踪就无法确定。