我正在尝试使用以下代码在Bar
类中重新定义2个方法:
private <T> Class<? extends T> replaceMethodInClass(final Class<T> subclass,
final ClassFileLocator classFileLocator, final String methodName) {
final Builder<? extends T> classBuilder =
this.bytebuddy.redefine(subclass, classFileLocator);
return classBuilder
.method(ElementMatchers.named(methodName))
.intercept(MethodDelegation.to(CustomInterceptor.class))
.make()
.load(ByteBuddyReplaceMethodInClassTest.class.getClassLoader(),
ClassReloadingStrategy.fromInstalledAgent())
.getLoaded();
}
CustomInterceptor
类如下:
static class CustomInterceptor {
public static String intercept() {
return "Hello!";
}
}
在我的测试中,我执行以下操作来重新定义Bar#sayHello()
和Bar#sayHelloAgain()
方法:
@Test
public void shouldReplaceTwoMethodsFromClass_instanciateAfterChanges()
throws InstantiationException, IllegalAccessException, Exception {
// given
replaceMethodInClass(Bar.class, ClassFileLocator.ForClassLoader.of(Bar.class.getClassLoader()),
"sayHello");
replaceMethodInClass(Bar.class, ClassFileLocator.ForClassLoader.of(Bar.class.getClassLoader()),
"sayHelloAgain");
// when
final Bar instance = Bar.class.newInstance();
final String hello = instance.sayHello();
final String helloAgain = instance.sayHelloAgain();
// then
assertThat(hello).isEqualTo("Hello!");
assertThat(helloAgain).isEqualTo("Hello!");
}
请注意,我明确要逐个替换方法。
测试失败,因为hello
变量为null
(这是Bar#sayHello()
类中Bar
方法返回的值),但helloAgain
变量已设置正如预期的那样Hello!
(使用了CustomInterceptor
类)。所以看起来第一种方法重新定义在第二种方法中被删除了。
您是否知道发生了什么以及如何在不丢失第一个方法的情况下保留2个方法的重新定义?
答案 0 :(得分:1)
这完全取决于您使用的ClassFileLocator
。您正在使用查询类加载器的类文件定位器。类加载器总是返回最初从类文件中可用的类文件,并且不知道任何转换。
如果要保留第一次转换的更改,则需要在类文件定位器中构建某种形式的内存以返回更改的类文件。您可以从dynamicType.getBytes()
读取转换生成的字节。
您还可以使用ClassFileLocator.AgentBased
使用Java检测API查找实时类文件,但需要附加Java代理。