注解式 AOP:@Aspect 与五类通知
引言
上一章建立了 AOP 术语。Spring 支持 AspectJ 风格的注解声明:用 @Aspect 标注切面类,用 @Pointcut 定义切点,再用五个通知注解挂在方法上,配一个开关即可运行。本章给出完整可跑的示例。
核心概念
- 开启方式:
@Configuration类上标@EnableAspectJAutoProxy(纯 Spring);Spring Boot 引入spring-boot-starter-aop后自动开启(以官方文档为准)。 - 切面类:
@Aspect+ 普通 Bean(@Component或@Bean注册)。 - 切点表达式:最常用
execution(修饰符? 返回类型 类名.方法名(参数)),如execution(public * com.example..service.*.*(..))表示任意返回值、service 包下所有类的所有方法。Spring AOP 支持的指示器包括 execution、within、target、args、this、@within、@target、@args、@annotation、bean,可用&& || !组合(以官方文档为准)。 - 通知注解与参数:
@Before("切点");@AfterReturning(pointcut, returning = "result")接收返回值;@AfterThrowing(pointcut, throwing = "ex")接收异常;@After:finally 语义;@Around:方法参数为ProceedingJoinPoint,pjp.proceed()放行并可改写返回值/捕获异常。
- 具名切点:
@Pointcut("execution(...)") private void svc() {},其他通知引用方法名即可复用。
代码示例
@Aspect
@Component
public class ServiceMonitor {
// 切点:service 包下任意类的任意方法
@Pointcut("execution(* com.example..service.*.*(..))")
private void serviceMethod() {}
@Before("serviceMethod()")
public void before() { System.out.println("调用前:开始计时/检查权限"); }
@AfterReturning(pointcut = "serviceMethod()", returning = "result")
public void afterReturn(Object result) { System.out.println("正常返回: " + result); }
@AfterThrowing(pointcut = "serviceMethod()", throwing = "ex")
public void afterThrow(Exception ex) { System.out.println("抛出异常: " + ex.getMessage()); }
@After("serviceMethod()")
public void after() { System.out.println("无论成败都执行:收尾"); }
@Around("serviceMethod()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
Object ret = pjp.proceed(); // 放行目标方法
System.out.println("耗时(ms): " + (System.nanoTime() - start) / 1_000_000);
return ret;
}
}
注意点
@Aspect类本身不参与自身切点匹配(避免自代理死循环),别在切面方法里再调自身切中方法。- 多个切面作用于同一方法时用
@Order(1)/@Order(2)控制执行顺序:数字小的先执行(Before 顺序与 Around/After 的包裹方向不同,以官方文档为准)。 @Around忘记proceed()等于拦截不放行;proceed()抛异常要按需转换,别擅自吞掉破坏事务语义。- 返回/异常绑定名必须与通知方法参数名一致,否则注入不了。
- 切点尽量收敛(包/注解限定),
execution(* *..*(..))全量匹配会拖累性能并引入意外副作用。
小结
@EnableAspectJAutoProxy 开开关,@Aspect + @Pointcut 定位置,五个通知注解定时机;@Around 最灵活、其余四个语义单一。先写窄切点、多打日志验证命中范围,再逐步加逻辑,是上手 AOP 最稳的路径。