我正在尝试通过 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)中排除
。否则,您将在重新转换尝试中包含该接口(interface)。由于这个原因,JVM 似乎会默默地使第二次重新转换失败,因为在加载类后无法将抽象方法更改为默认方法。通常,这会触发异常,但在您的情况下,虚拟机似乎默默地抑制了错误。say
方法来优化方法匹配器说“))
关于java - 如何应用、删除和重新应用 bytebuddy 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42804253/