重新定义方法会覆盖以前的重新定义

时间:2016-11-29 18:59:03

标签: java byte-buddy

我正在尝试使用以下代码在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个方法的重新定义?

1 个答案:

答案 0 :(得分:1)

这完全取决于您使用的ClassFileLocator。您正在使用查询类加载器的类文件定位器。类加载器总是返回最初从类文件中可用的类文件,并且不知道任何转换。

如果要保留第一次转换的更改,则需要在类文件定位器中构建某种形式的内存以返回更改的类文件。您可以从dynamicType.getBytes()读取转换生成的字节。

您还可以使用ClassFileLocator.AgentBased使用Java检测API查找实时类文件,但需要附加Java代理。