Byte Buddy中无法向Advice传递Method对象的技术问题
JDK21下Byte Buddy Advice注入Method对象失败的解决方案
问题场景
在JDK21环境搭配最新版Byte Buddy时,编写如下TimingAdvice类,尝试通过@Advice.Origin注入Method对象到方法进入逻辑中:
package plugin; import java.lang.reflect.Method; import net.bytebuddy.asm.Advice; public class TimingAdvice { @Advice.OnMethodEnter public static void onEnter(@Advice.Origin Method method) throws Throwable { System.out.println("method: " + method); } }
转换SomeAdvisedClass类时触发报错:
Failed to transform class SomeAdvisedClass: [java.lang.IllegalStateException: Cannot map this reference for static method or constructor start: public SomeAdvisedClass()].
改为注入类型名和方法名字符串后代码可正常运行,但业务需要获取Method对象以检查参数上的注解,需解决该问题。
报错原因
报错核心原因是Advice规则匹配到了目标类的构造方法,而构造方法对应的反射类型是Constructor而非Method,直接注入Method会导致类型不匹配,触发映射异常。
解决方案
方案一:过滤构造方法,仅匹配普通方法
修改Byte Buddy的匹配规则,排除构造方法,让Advice只作用于普通方法。以Plugin实现为例:
public class TimingPlugin implements Plugin { @Override public void apply(Plugin.Builder builder, TypeDescription typeDescription, ClassFileLocator classFileLocator) { builder.visit(Advice.to(TimingAdvice.class) .on(not(isConstructor()))); // 排除构造方法,仅匹配普通方法 } @Override public boolean matches(TypeDescription target) { // 按需定义目标类匹配规则 return target.getName().equals("SomeAdvisedClass"); } @Override public void close() throws IOException {} }
此时原TimingAdvice的代码可正常运行,Method对象能正确注入。
方案二:兼容构造方法与普通方法,注入父类Executable
如果需要同时处理构造方法和普通方法,可注入Executable类型(Method和Constructor的共同父类),在代码中区分类型处理:
package plugin; import java.lang.reflect.Executable; import java.lang.reflect.Method; import net.bytebuddy.asm.Advice; public class TimingAdvice { @Advice.OnMethodEnter public static void onEnter(@Advice.Origin Executable executable) throws Throwable { if (executable instanceof Method method) { // 处理普通方法,检查参数注解 System.out.println("method: " + method); // 示例:遍历并打印参数注解 for (int i = 0; i < method.getParameterCount(); i++) { System.out.println("参数" + i + "的注解列表:" + method.getParameterAnnotations()[i]); } } // 如需处理构造方法,可添加else分支 } }
这种方式能覆盖所有可执行元素,同时满足获取方法对象检查参数注解的需求。
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

