我正在尝试了解Advice.withCustomMapping().bind(...)
的用途和用途,以查看它是否对我的用例有用。
读取Advice.withCustomMapping()
的javadoc:
允许配置自定义注释,然后将其绑定到动态计算的恒定值。
这是我要应用此模式的用例:
public @interface Name {
}
public abstract class AgentRule {
private final String className = getClass().getName();
public final Advice.WithCustomMapping advice() {
return Advice.withCustomMapping().bind(Name.class, className);
}
public static boolean isEnabled(final String className, final String origin) {
...
}
public abstract Iterable<? extends AgentBuilder> buildAgent(AgentBuilder builder) throws Exception;
}
public class ServletContextAgentRule extends AgentRule {
public static boolean filterAdded = false;
@Override
public Iterable<? extends AgentBuilder> buildAgent(final AgentBuilder builder) throws Exception {
return Arrays.asList(builder
.type(named("org.eclipse.jetty.servlet.ServletContextHandler"))
.transform(new Transformer() {
@Override
public Builder<?> transform(final Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(advice().to(JettyAdvice.class).on(isConstructor()));
}})
.type(not(isInterface()).and(hasSuperType(named("javax.servlet.ServletContext"))
// Jetty is handled separately due to the (otherwise) need for tracking state of the ServletContext
.transform(new Transformer() {
@Override
public Builder<?> transform(final Builder<?> builder, final TypeDescription typeDescription, final ClassLoader classLoader, final JavaModule module) {
return builder.visit(advice().to(ServletContextAdvice.class).on(isConstructor()));
}}));
}
public static class JettyAdvice {
@Advice.OnMethodExit
public static void exit(final @Name String className, final @Advice.Origin String origin, final @Advice.This Object thiz) {
if (isEnabled(className, origin))
filterAdded = JettyAgentIntercept.addFilter(thiz);
}
}
public static class ServletContextAdvice {
@Advice.OnMethodExit
public static void exit(final @Name String className, final @Advice.Origin String origin, final @Advice.This Object thiz) {
if (isEnabled(className, origin))
filterAdded = ServletContextAgentIntercept.addFilter(thiz);
}
}
}
有效地,我要做的是将信息从ServletContextAgentRule
的实例上下文中继到JettyAdvice
和ServletContextAdvice
的静态上下文。由于建议方法应该是静态的,因此我无法找到一种将实例状态纳入这些方法的方法(没有有效地构建涉及类实例映射的某种外部中继机制,从而导致AgentRule
的所有子类中都有复制粘贴的代码) 。此用例正在应用于涉及a lot of rules的项目,这就是为什么我试图找出执行此操作的最高性能和最简洁的方法。
[当我尝试使用Advice.withCustomMapping().bind(...)
这种方法时,我从ByteBuddy收到一个异常说:
java.lang.IllegalStateException: org.eclipse.jetty.servlet.ServletContextHandler() does not define an index 0
Advice.withCustomMapping().bind(...)
的目的仅是覆盖方法签名中存在的特定参数吗?我在javadocs中找不到提及此内容,并且在网上查看其他示例,我似乎认为我的用例应该可以工作。
您需要
@Retention(RUNTIME)
public @interface Name { }
否则,Buddy Byte Buddy将看不到您的注释,并退回到默认值,即带有相同索引的参数。