SpringBoot中@annotation切面无法作用于MyBatis DAO接口问题咨询
问题原因
- MyBatis的DAO(Mapper)层接口的实现类是运行时动态生成的JDK/CGLIB代理类,Java原生特性中,接口方法上的注解不会被实现类的对应方法继承,哪怕给自定义注解加了
@Inherited元注解也不生效——@Inherited仅支持类级别的注解继承,对方法级注解无效。 - Spring AOP默认的
@annotation切点匹配逻辑是校验当前被调用的实际代理类的方法上是否存在对应注解,而动态生成的Mapper实现类方法上并没有继承接口上的@TestAnnotation,因此匹配失败,切面不会触发。 - execution类型的切点仅根据方法签名、包路径等规则匹配,不需要校验注解存在,所以可以正常命中DAO层方法;Service、Controller的方法注解都是直接写在你自己实现的类方法上,不是接口方法,因此
@annotation可以正常匹配。
解决方案
方案1:修改切点表达式为带注解校验的execution规则
直接用execution同时匹配方法签名和接口方法上的注解,该规则会自动向上查询接口方法的注解,不需要依赖实现类继承:
// 替换原有@Around的切点表达式,xxx替换为你自己的DAO层包路径、注解的全限定类名 @Around("execution(@com.xxx.annotation.TestAnnotation * com.xxx.dao..*.*(..))") public Object doSomethingAround(ProceedingJoinPoint joinPoint) throws Throwable { // 原有逻辑不变 Object result = joinPoint.proceed(); return result; }
该方案改造成本最低,不需要改动其他配置。
方案2:切面内手动校验接口方法注解
先通过execution匹配所有DAO层方法,再在切面逻辑里主动获取对应接口方法的注解,判断是否存在@TestAnnotation再执行对应逻辑:
@Around("execution(* com.xxx.dao..*.*(..))") public Object doSomethingAround(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取当前方法对应的接口方法对象 Method method = signature.getMethod(); TestAnnotation anno = null; if (method.getDeclaringClass().isInterface()) { anno = method.getAnnotation(TestAnnotation.class); } else { // 兼容实现类方法直接加注解的场景 anno = method.getAnnotation(TestAnnotation.class); } if (anno != null) { // 执行你的切面前置逻辑 } Object result = joinPoint.proceed(); // 后置逻辑同理判断执行 return result; }
方案3:切换为AspectJ编译时织入
如果需要统一用@annotation规则适配所有层的切面,可将Spring AOP替换为完整的AspectJ,开启编译时织入,在编译阶段就将切面逻辑织入接口对应的调用点,不需要依赖运行时代理的注解继承。
该方案需要额外引入AspectJ编译插件,调整项目构建配置,改造成本相对更高。
内容的提问来源于stack exchange,提问作者Jin
相关产品推荐
相关产品推荐

