1

我正在尝试使用 ByteBuddy 重新定义 2 种方法,如下所示:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
ClassLoadingStrategy.Default classLoadingStrategy = ClassLoadingStrategy.Default.INJECTION;
new ByteBuddy().redefine(CommandBase.class).method(returns(Item.class)).intercept(MethodDelegation.to(CppItemInterceptor.class)).make().load(classLoader, classLoadingStrategy);
new ByteBuddy().redefine(CommandBase.class).method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class)).make().load(classLoader, classLoadingStrategy);
try {
    System.out.println(CppBlockInterceptor.getBlockByText(null, "1").getLocalizedName());
    System.out.println(CommandBase.getBlockByText(null, "1").getLocalizedName());
} catch (Exception e) {
    e.printStackTrace();
}

对 CppBlockInterceptor 的直接调用会产生预期的输出,但对应该被替换的方法的调用仍然使用旧行为。这有什么原因吗?

4

2 回答 2

2

在您有机会重新定义它之前,您CommandBase的类已经加载。Byte Buddy 不能在不使用 Java 代理的情况下替换已加载的类。尝试运行这个:

TypeDescription commandBase = new TypePool.Default.ofClassPath()
    .locate("my.package.CommandBase");
new ByteBuddy()
  .redefine(commandBase, ClassFileLocator.ForClassLoader.ofClassPath())
  .method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class))
  .make()
  .load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTOR);

CppBlockInterceptor.getBlockByText(null, "1").getLocalizedName()

在调用之前没有明确CommandBase引用,它将起作用。不过,最好使用一个AgentBuilder和一个 Java 代理。Byte Buddy的文档解释了原因

于 2015-07-16T13:30:47.297 回答
0

接受的答案不再可编译(因为已经过去了 5 年多,这并不奇怪)。使用 Byte Buddy v1.10.17 的正确代码如下:

TypeDescription typeDescription = TypePool.Default.ofSystemLoader()
    .describe("my.package.CommandBase")
    .resolve();
new ByteBuddy()
    .redefine(typeDescription, ClassFileLocator.ForClassLoader.ofSystemLoader())
    .method(returns(Block.class)).intercept(MethodDelegation.to(CppBlockInterceptor.class))
    .make()
    .load(ClassLoader.getSystemClassLoader(), ClassLoadingStrategy.Default.INJECTION);
于 2020-10-18T13:31:54.743 回答