@AfterThrowing切面通过throwing属性和同名参数捕获异常,需确保参数名一致、类型为Throwable或其子类,且切点匹配抛出未捕获异常的目标方法。

在 Spring AOP 中,@AfterThrowing 切面能捕获目标方法抛出的异常,但要正确获取该异常,关键在于 切点表达式和通知方法参数的声明方式,而不是直接依赖 throw 关键字本身(throw 是 Java 语句,用于主动抛出异常,不参与 AOP 异常捕获机制)。
1. 正确声明 @AfterThrowing 的 throwing 参数
@AfterThrowing 注解必须通过 throwing 属性指定一个参数名,并在通知方法中用同名参数接收异常对象。Spring AOP 会自动将被拦截方法抛出的异常注入该参数。
- 切点表达式无需显式匹配异常类型,只需定位目标方法即可
- 通知方法中对应参数类型应为
Throwable或其子类(如Exception、RuntimeException),推荐用Throwable以捕获所有异常 - 参数名必须与
throwing属性值严格一致
2. 示例代码
以下是一个标准写法:
@Aspect
@Component
public class LoggingAspect {
<pre class="brush:php;toolbar:false;">@AfterThrowing(pointcut = "execution(* com.example.service..*.*(..))",
throwing = "ex")
public void logException(Throwable ex) {
System.err.println("捕获异常: " + ex.getClass().getSimpleName());
System.err.println("异常消息: " + ex.getMessage());
ex.printStackTrace(); // 可选:打印堆栈
}}
立即学习“Java免费学习笔记(深入)”;
说明:
- throwing = "ex" 告诉 Spring 把抛出的异常赋给名为 ex 的参数
- 方法签名中 logException(Throwable ex) 的 ex 就是实际抛出的异常实例
- 即使原方法用 throw new IllegalArgumentException("xxx") 主动抛出,这里也能接收到
3. 常见错误与注意事项
- 参数名不匹配:若注解写
throwing = "error",但方法参数叫ex,则参数为null,不会报错但无法获取异常 - 参数类型太窄:声明为
Exception ex时,若目标方法抛出Error(如OutOfMemoryError),该通知不会触发(因为Error不是Exception的子类) - 切点未覆盖目标方法:确保
execution表达式能匹配到实际抛出异常的方法,否则通知根本不会执行 -
@AfterThrowing只对“抛出后未被捕获”的异常生效;如果方法内try-catch吞掉了异常,AOP 就捕获不到
4. 配合 throw 使用的典型场景
你可以在业务逻辑中用 throw 主动抛异常,再由 AOP 统一处理:
@Service
public class UserService {
public void deleteUser(Long id) {
if (id == null) {
throw new IllegalArgumentException("ID 不能为空");
}
// ... 删除逻辑
}
}此时 @AfterThrowing 通知中的 ex 就是这个 IllegalArgumentException 实例,可做日志、告警或转换为统一响应。


















