AOP 基本概念:切点、通知类型与织入时机
引言
日志、鉴权、性能统计这类横切逻辑如果逐个方法手写,会散落且重复。AOP(面向切面编程)把“横切关注点”从业务代码里抽出来,在方法执行的特定位置统一织入。本章先建立术语与织入时机的时间线,第 11 章再上注解写法。
核心概念
- Aspect(切面):横切逻辑的模块化单元(一组通知 + 一组切点)。
- Join Point(连接点):可被织入的位置。Spring AOP 中即“Spring Bean 的 public 方法执行”。
- Pointcut(切点):用表达式挑选“哪些连接点生效”。
- Advice(通知):切点命中后在目标方法执行的某个时机运行的代码,官方区分五种:
- Before:方法调用前;
- AfterReturning:正常返回后;
- AfterThrowing:抛出异常后;
- After(finally):无论正常/异常都执行;
- Around:包围目标方法,可完全控制(含是否放行)。
- Target(目标对象):被代理的真实 Bean。
- Proxy(代理):Spring AOP 运行时为目标对象生成代理,调用经由代理才能触发通知。
- Weaving(织入):把通知与目标代码合成为可运行逻辑的动作,分三种时机:编译期(AspectJ 编译器 ajc)、类加载期(LTW)、运行期(Spring AOP 默认,靠代理实现)。
- Spring AOP 只支持“方法执行”连接点,且只对 Spring 管理的 Bean 生效;完整 AspectJ(字段读写、构造器等连接点)超出 Spring AOP 范围。
代码示例
// 用接口隔离横切目标:只有通过代理的调用才会触发通知
public interface Calculator {
int add(int a, int b);
}
@Component
public class CalculatorImpl implements Calculator {
public int add(int a, int b) {
if (a < 0 || b < 0) throw new IllegalArgumentException("负数不支持");
return a + b;
}
}
// 时间线演示(伪代码,标注五种通知在方法执行周期的位置):
// [Before] → add(...) 执行 → [AfterReturning / AfterThrowing]
// └──────── [After(final)] ────────┘
// [Around] 包裹以上整个过程:proceed() 之前=Before 语义,之后=返回/异常语义
注意点
- Spring AOP 是运行期代理织入:对象必须是 Spring Bean,调用必须从外部穿过代理(自调用失效见第 13 章)。
- 只有 public 方法能被代理拦截;private/final/static 方法不在 Spring AOP 能力内(以官方文档为准)。
- “After”与“AfterReturning”不同:前者 finally 语义,后者仅在正常返回时触发,异常时 AfterThrowing 触发。
- 通知顺序:Around 是包裹层,可视为 before/after 语义的合成;多个切面叠加时顺序受
@Order控制(下一章)。 - 编译期/加载期织入属于 AspectJ 本身能力,需要用 AspectJ 编译器或 LTW 时才引入,日常 Boot/Spring 项目用 Spring AOP 即可。
小结
AOP 用“切点选位置、通知定时机、代理做织入”解决横切关注点:五种通知对应方法执行的五个时机,Spring AOP 在运行期通过代理实现、只认 Spring Bean 的 public 方法。术语体系建立后,下一章写真正可跑的 @Aspect。