重新定义一个方法覆盖以前的重新定义
问题描述:
我尝试使用下面的代码重新定义一个类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
类的Bar#sayHello()
方法返回的值),但helloAgain
变量被设置为Hello!
,如所预期(使用了CustomInterceptor
类)。所以看起来第一个方法重定义在第二个方法时被删除了。
你有什么想法发生了什么,以及如何保持2方法重新定义,而不是丢失第一个?
答
这一切都取决于您正在使用的ClassFileLocator
。您正在使用查询类加载器的类文件定位器。类加载器始终返回最初可从类文件中获得的类文件,并且不知道任何转换。
如果要保留第一次转换的更改,则需要在类文件定位器中构建某种形式的内存以返回已更改的类文件。您可以读取从dynamicType.getBytes()
转换生成的字节。
您还可以查看使用Java API的仪器现场的类文件通过ClassFileLocator.AgentBased
这确实需要但附加一个Java代理。
感谢您的回应,拉斐尔!所以,为了保持以前的变化,我可以使用基于目录(即ClassFileLocator:'新ClassFileLocator.ForFolder(this.classDir)',在这我每一个方法被重新定义时间节省类的字节码? –
是的,这可能是最可靠的方法。 –
是的,的确,我是能够做到这样的,它再完美的作品。感谢您的支持,拉斐尔! –