如何自定义AspectJ切点表达式,实现动态添加@Trace注解并满足多约束
问题与解决方案
1. 满足所有条件的切点表达式写法
你需要把所有条件整合到AspectJ的declare @method切点中,正确的表达式如下:
package com.example.apectitddemo.aspect; import org.springframework.stereotype.Controller; import com.example.apectitddemo.annotation.Disable; import com.example.apectitddemo.annotation.Trace; public aspect TracingAspect { declare @method : public * com.example.apectitddemo.controller.@Controller *.*(..) && !@Disable : @Trace; }
各部分对应条件的说明:
public *:匹配所有公共方法(满足条件1)com.example.apectitddemo.controller.:限定类必须在指定包下(满足条件3)@Controller *:匹配标注了@Controller的类(满足条件2).*(..):匹配类下任意参数的方法&& !@Disable:排除标注了@Disable的方法(满足条件4)
2. 能否用纯Java编写而非.aj文件?
不行。AspectJ的ITD(Inter Type Declaration)特性仅支持AspectJ原生语法(.aj文件),纯Java的Spring AOP基于动态代理,只能实现方法拦截逻辑,无法直接通过代码给目标方法添加注解(这属于字节码级别的修改)。如果一定要用纯Java实现类似效果,只能借助ASM、ByteBuddy这类字节码增强框架,但实现复杂度远高于AspectJ ITD。
3. 更优的实现方式
分两种场景选择:
场景1:必须实际添加@Trace注解
最优方案就是上面的AspectJ ITD写法,编译期织入字节码,性能损耗极小,代码简洁直接,能自动给新增方法添加注解,完全符合需求。
场景2:只需实现@Trace的逻辑(无需实际添加注解)
可以用纯Java的Spring AOP切面替代,无需AspectJ编译插件,实现起来更轻量化:
package com.example.apectitddemo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import com.example.apectitddemo.annotation.Disable; @Aspect @Component public class TracingAspect { // 定义切点,匹配所有符合条件的方法 @Pointcut("execution(public * com.example.apectitddemo.controller.@Controller *.*(..)) && !@annotation(Disable)") public void traceableMethods() {} // 实现@Trace对应的逻辑,比如方法调用前打印追踪日志 @Before("traceableMethods()") public void beforeMethodExecution(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); String className = joinPoint.getTarget().getClass().getSimpleName(); System.out.printf("Trace: Calling %s.%s()%n", className, methodName); } }
这种方式的好处是纯Java编写,无需额外配置AspectJ编译插件,缺点是不会给方法实际添加@Trace注解,仅实现注解的行为逻辑。
内容的提问来源于stack exchange,提问作者studentttt
相关产品推荐
相关产品推荐

