一、AOP 基础概念
1. 什么是 AOP
AOP(Aspect Oriented Programming)即面向切面编程,核心思想:不修改原有业务代码,对指定方法进行功能增强。 AOP 是一种编程思想,Spring AOP 是该思想在 Spring 框架中的落地实现,底层基于动态代理技术。
2. 核心优势
- 减少重复代码,通用逻辑统一维护
- 对业务代码零侵入,不影响原有业务逻辑
- 提升开发效率,降低后期维护成本
3. 典型应用场景
- 统计业务方法执行耗时
- 系统操作日志记录
- 声明式事务管理(@Transactional底层实现)
- 接口权限统一校验
二、SpringAOP 快速入门:方法耗时统计
实现步骤
完整代码示例
1)引入依赖
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-aop</artifactid>
</dependency>
2)切面类实现
@aspect
@component
public class recordtimeaspect {
// 环绕通知 + 切入点表达式:匹配service.impl下所有类的所有方法
@around("execution(* com.itheima.service.impl.*.*(..))")
public object recordtime(proceedingjoinpoint pjp) throws throwable {
// 1. 记录方法开始时间
long begin = system.currenttimemillis();
// 2. 执行原始目标方法
object result = pjp.proceed();
// 3. 计算并打印耗时
long end = system.currenttimemillis();
system.out.println("方法执行耗时:" + (end – begin) + "ms");
// 返回方法执行结果
return result;
}
}
三、AOP 五大核心概念
| 连接点 JoinPoint | 所有可以被 AOP 增强的方法(候选方法集合) |
| 通知 Advice | 额外增强的业务逻辑(比如统计耗时、记录日志的代码) |
| 切入点 PointCut | 匹配规则,筛选出真正需要增强的连接点 |
| 切面 Aspect | 切面 = 通知 + 切入点,封装增强逻辑与匹配规则 |
| 目标对象 Target | 被增强功能的原始业务对象 |
底层原理:Spring 基于动态代理自动生成代理对象,替换原始对象注入 IOC 容器;方法调用时实际执行代理对象,先执行增强逻辑,再调用原方法。
四、五大通知类型详解
根据执行时机不同,通知分为五类,其中环绕通知功能最强大:
| @Around 环绕通知 | 目标方法执行前后都可执行 | 功能最强,需手动调用proceed()触发原方法,必须返回结果 |
| @Before 前置通知 | 目标方法执行之前运行 | 无法阻止方法执行,仅做前置准备 |
| @After 后置通知 | 目标方法执行完毕后运行 | 无论方法正常结束还是抛出异常,都会执行 |
| @AfterReturning 返回后通知 | 方法正常返回结果后运行 | 方法抛出异常则不执行,可获取方法返回值 |
| @AfterThrowing 异常通知 | 方法抛出异常后运行 | 仅异常场景触发,可捕获异常信息 |
⚠️ 关键注意事项:
- @Around 必须手动调用 pjp.proceed(),否则原始方法不会执行
- @Around 必须返回Object类型结果,否则接口无法获取返回数据
五、切入点表达式
1. execution 表达式(最常用)
根据包名、类名、方法名批量匹配方法。
语法格式
execution(返回值类型 包名.类名.方法名(参数类型))
通配符说明
- *:匹配任意返回值、任意类、任意方法名
- ..:匹配任意类型、任意个数的参数
// 匹配service.impl包下所有类的所有方法
execution(* com.itheima.service.impl.*.*(..))
2. @annotation 注解匹配
匹配标注了指定自定义注解的方法,粒度更灵活。
// 匹配所有加了@Log注解的方法
@around("@annotation(com.itheima.anno.log)")
适用场景:零散分布的增强需求,比如指定部分接口记录操作日志。
六、@Pointcut 切入点抽取
作用
将重复的切入点表达式抽取为独立方法,实现复用,简化代码。
代码示例
// 抽取公共切入点
@pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt(){}
// 直接引用切入点方法
@around("pt()")
public object recordtime(proceedingjoinpoint pjp) throws throwable {
// 增强逻辑
}
访问权限
- private:仅当前切面类内部可引用
- public:其他切面类也可以引用该切入点
七、JoinPoint 连接点对象
两类对象区别
- JoinPoint:适用于前置、后置等普通通知,可获取方法基本信息
- ProceedingJoinPoint:仅适用于@Around环绕通知,继承自 JoinPoint,额外支持proceed()执行原方法
常用方法
// 获取目标类对象
object target = joinpoint.gettarget();
// 获取方法签名、方法名
string methodname = joinpoint.getsignature().getname();
// 获取方法入参数组
object[] args = joinpoint.getargs();
八、ThreadLocal 线程局部变量
核心特性
ThreadLocal 不是线程,而是线程级别的局部存储变量,为每个线程提供独立的存储空间,线程之间数据完全隔离,互不干扰。
核心 API
| set(object value) | 向当前线程存入数据 |
| get() | 读取当前线程存储的数据 |
| remove() | 移除当前线程的数据 |
典型实战:登录用户信息传递
一次请求对应一个线程,在过滤器解析登录信息后存入 ThreadLocal,后续 Controller、Service、AOP 均可直接获取,无需层层传参。
工具类封装
public class currentholder {
private static final threadlocal<integer> current_local = new threadlocal<>();
public static void setcurrentid(integer empid){
current_local.set(empid);
}
public static integer getcurrentid(){
return current_local.get();
}
public static void remove(){
current_local.remove();
}
}
使用流程
⚠️ 强制注意:使用完毕必须调用 remove (),否则线程复用会导致数据错乱,引发内存泄漏。
九、实战案例:操作日志记录
需求
将系统中增、删、改接口的操作信息记录到数据库,包含:操作人、操作时间、执行方法、请求参数、返回值、执行时长。
实现方案
十、开发避坑指南 ⚠️
十一、文末总结
AOP 是 Spring 框架三大核心特性之一,通过动态代理实现代码无侵入增强,是企业开发中解耦通用逻辑的核心手段。 掌握五大通知类型、两种切入点表达式写法,结合 ThreadLocal 实现上下文数据传递,即可覆盖绝大多数 AOP 业务场景,也是 Spring 事务、日志、权限等组件的底层基础。
网硕互联帮助中心
![P1014 [NOIP 1999 普及组] Cantor 表-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/08/20260811104049-6a7afc31a3c58-220x150.png)

评论前必须登录!
注册