java - 如何应用、删除和重新应用 bytebuddy 转换?

标签 java byte-buddy

我正在尝试通过 javaagent 应用、删除和重新应用 bytebuddy 转换,如下代码所示。通过 ResettableClassFileTransformer::reset 可以正常删除,但重新应用不起作用。

// The target classes

public @interface ToString {
}

public interface Greetable {
    String say(final String name);
}

@ToString
public class Greeter implements Greetable {
     public String say(final String name) {
         return "Hello " + name;
     }
}
//note the some transform is from the example
new AgentBuilder.Transformer() {
  @Override
  public DynamicType.Builder transform(DynamicType.Builder builder,
                                       TypeDescription     typeDescription,
                                       ClassLoader         classloader,
                                       JavaModule          module) {
    return builder.method(named("say"))
                  .intercept(FixedValue.value("transformed");
  }
})
// The transformation
public class MyProgram {
    public static void main(final String[] args) {
        ByteBuddyAgent.install();
        AgentBuilder bldr = new AgentBuilder.Default().
                                             with(AgentBuilder.Listener.
                                                      StreamWriting.
                                                      toSystemOut()).
                                             with(RedefinitionStrategy.
                                                     RETRANSFORMATION).
                                             disableClassFormatChanges().
                                             type(isSubTypeOf(
                                                       Greetable.class)).
                                             transform(<some transform>);
        ResettableClassFileTransformer resetter = 
                                          bldr.installOnByteBuddyAgent();
        Greetable g1 = new Greeter();
        System.out.println(g1.say("001"));

        //remove the transformation
        resetter.reset(ByteBuddyAgent.getInstrumentation(),
                       RedefinitionStrategy.RETRANSFORMATION);
        Greetable g2 = new Greeter();
        System.out.println(g2.say("002"));

        //re-apply the transformation
        bldr.installOn(ByteBuddyAgent.getInstrumentation());
        Greetable g3 = new Greeter();
        System.out.println(g3.say("003"));

    }
}

输出为

TRANSFORM Greetable [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                     null,
                     loaded=true]
TRANSFORM Greeter [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                   null,
                   loaded=true]
transformed //note: the g1.say() is transformed.

Hello 002         //note: the g2 is an orginal

TRANSFORM Greetable [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                     null,
                     loaded=true]
TRANSFORM Greeter [sun.misc.Launcher$AppClassLoader@7ab2bfe1,
                   null,
                   loaded=true]
Hello 003         //note the re-apply has not worked.

您能否帮忙指导一下如何实现重新申请?

编辑1

我已将 byte-buddy 更新至版本 1.6.11 并更改了 AgentBuilder.Transformer。结果还是一样。 g3.say() 未转换。

我的环境是

Windows 10 64Bits

java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

编辑2

我已经从界面更改了类型匹配器

type(isSubTypeOf(Greetable.class))

具体类为

type(isSubTypeOf(Greeter.class))

g3.say() 已转换属性。接口(interface)匹配和转换有限制吗?

最佳答案

正如我从 AgentBuilder.Transformer API 中可以看出的那样,您正在运行旧版本的 Byte Buddy。我刚刚尝试了最新版本,它可以工作。

在实践中,您是否依赖@ToString注释来触发转换?当您转换尚未加载的类时,Byte Buddy 会直接从类文件中读取注释。对于加载的类,它使用加载的表示形式。您的注释未使用 @RetentionPolicy(Retention.RUNTIME) 进行注释以保留注释可见性,这可能是问题所在。

更新:您需要通过 not(isAbstract()).and(named(") 从接口(interface)中排除 say 方法来优化方法匹配器说“))。否则,您将在重新转换尝试中包含该接口(interface)。由于这个原因,JVM 似乎会默默地使第二次重新转换失败,因为在加载类后无法将抽象方法更改为默认方法。通常,这会触发异常,但在您的情况下,虚拟机似乎默默地抑制了错误。

关于java - 如何应用、删除和重新应用 bytebuddy 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42804253/

相关文章:

java - 实现类,等腰三角形

java - 如何使用 gson.fromjson 递归地转换 json

java - 使用 byte buddy 或某些库进行分析

java - 如何使用 ByteBuddy 代理处理构造函数抛出的异常?

java - Byte Buddy 为构造函数实例化不带参数的类

java - Hadoop 作业执行所花费的时间

java - 如何将 Consumer<String> 传递给方法

java - 如何打开命令提示符并从 java 程序输入不同的命令

java - 用 ByteBuddy 修饰方法

java - ByteBuddy - 转换所有方法