一篇搞懂 Spring AOP:从原理到实战,小白也能看懂
一篇搞懂 Spring AOP:从原理到实战,小白也能看懂
一、什么是 Spring AOP?
Spring AOP 是 Spring 框架的核心模块之一,是 面向切面编程(Aspect-Oriented Programming) 在 Java 生态中的经典实现。
要理解 AOP,我们先从日常开发的痛点说起:
在 Java 的面向对象编程(OOP)中,我们用类封装核心业务逻辑,比如用户登录、订单增删改查,这些是核心业务。但同时,我们总会遇到大量和核心业务无关、却又在多个业务中重复出现的逻辑:比如接口日志打印、全局事务管理、接口权限校验、异常统一处理等,这些是周边功能。
如果把这些周边功能硬编码到核心业务代码里,会出现两个严重问题:
- 代码冗余:每个业务方法都要写一遍日志、事务代码,维护成本极高
- 耦合严重:核心业务和周边功能强绑定,修改日志逻辑要改所有业务代码
AOP 的出现,就是为了解决这个问题:把核心业务和周边功能完全解耦,独立开发,最后再通过 “织入” 的方式把两者结合起来。
简单来说,AOP 就像给代码 “打补丁”:不用修改核心业务的源码,就能给所有符合条件的方法,统一加上日志、事务、权限等增强逻辑。
二、AOP 的核心思想:核心业务与周边功能分离
AOP 的核心思想,是把系统功能拆分为两类完全独立的模块:
- 核心业务:用户登录、订单创建、数据增删改查等,是系统的核心价值所在
- 周边功能(横切逻辑):日志、事务、权限、缓存、监控等,是所有核心业务都需要的通用能力
AOP 的优势非常明显:
减少重复代码:通用逻辑只写一次,不用在每个业务方法里重复编写
降低耦合度:核心业务只关注业务本身,不用关心周边功能的实现
提升可维护性:修改通用逻辑,只需要改切面代码,不用动所有业务代码
增强可扩展性:新增通用能力,直接加切面即可,无需修改现有业务
三、AOP 的 7 个核心概念(面试必背 + 通俗解释)
1. Aspect(切面)
通俗解释:切面是封装横切逻辑的 “容器”,是 Join point、Advice、Pointcut 的统称,一个切面就对应一个完整的横切功能(比如日志切面、事务切面)。
面试一句话:Aspect 是切面,是横切逻辑的模块化封装,包含了通知、切点等所有 AOP 组件。
2. Join point(连接点)
通俗解释:程序执行过程中可以被 AOP 拦截的 “时机”,最常见的就是方法调用,也包括异常处理、构造器调用等。注意:Spring AOP 仅支持方法级别的连接点。
面试一句话:Join point 是连接点,指程序中可以被 AOP 拦截的执行点,Spring AOP 中仅支持方法调用作为连接点。
3. Advice(通知 / 增强)
通俗解释:切面中具体要执行的横切逻辑,也就是我们写的日志、事务代码。Spring AOP 中常见的通知类型有 3 种:
-
@Before:方法执行前执行(比如入参日志打印) -
@After:方法执行后执行(比如返回值日志打印) -
@Around:环绕通知,可在方法前后自定义逻辑,功能最强大面试一句话:Advice 是通知,是切面中具体的横切逻辑,定义了在连接点要执行的操作,常见类型有 before、after、around。
4. Pointcut(切点)
通俗解释:用来筛选连接点的 “规则”,通过切点表达式(比如execution(* com.example.service.*.*(..))),决定哪些方法会被 AOP 拦截、执行通知逻辑。
面试一句话:Pointcut 是切点,通过表达式匹配符合条件的连接点,筛选出需要被增强的目标方法。
5. Introduction(引介)
通俗解释:AOP 的特殊增强能力,不用修改目标类的源码,就能给目标类动态实现额外的接口、新增方法,相当于给类 “开外挂”。
面试一句话:Introduction 是引介,可在运行时给目标类动态实现新接口,无需修改源码即可扩展功能。
6. Weaving(织入)
通俗解释:把切面逻辑应用到目标方法的过程,是 AOP 生效的核心动作。Spring AOP 采用运行时织入,通过动态代理实现,无需修改源码、无需编译期处理。
面试一句话:Weaving 是织入,是将切面逻辑插入目标方法、生成代理对象的过程,Spring AOP 基于运行时织入实现。
7. AOP proxy(AOP 代理)& Target object(目标对象)
-
Target object(目标对象):被 AOP 代理、被增强的原始业务对象,是真正执行业务逻辑的本体
-
AOP proxy(AOP 代理):Spring AOP 生成的代理对象,是目标对象的 “替身”,承载了切面逻辑,对外提供服务。Spring AOP 支持两种代理:
-
JDK 动态代理:基于 Java 反射,要求目标类必须实现接口
-
CGLIB 动态代理:基于 ASM 字节码框架,通过继承目标类生成代理,无需接口,性能更优
面试一句话:Target 是被代理的原始业务对象,AOP proxy 是 Spring 生成的代理对象,Spring AOP 基于 JDK 动态代理和 CGLIB 动态代理两种方式实现。
-
四、Spring AOP 的实现原理:动态代理
Spring AOP 的核心实现,是运行时动态代理,这也是它和 AspectJ 的核心区别:
- Spring AOP:基于 JDK 动态代理和 CGLIB 动态代理,运行时生成代理对象,无需编译期处理,纯 Java 代码实现,无侵入性
- AspectJ:支持编译期、类加载期织入,需要特殊编译器,功能更强大,但侵入性高
两种代理的核心区别
| 代理类型 | 实现原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| JDK 动态代理 | 基于 Java 反射,实现目标类的接口 | 目标类实现了接口 | 无需额外依赖,性能一般 |
| CGLIB 动态代理 | 基于 ASM 字节码,继承目标类 | 目标类未实现接口 | 性能更优,Spring 5.x 默认优先使用 |
Spring 会自动适配:如果目标类实现了接口,用 JDK 代理;如果没有实现接口,自动切换为 CGLIB 代理,对业务代码完全透明。
五、Spring AOP 实战:一个日志切面 Demo
我们用一个最简单的例子,把上面的概念落地,直接可运行:
1. 引入依赖(Spring Boot 项目)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 定义核心业务类(Target object)
@Service
public class UserService {
// 目标方法:核心业务,登录逻辑
public String login(String username, String password) {
System.out.println("执行核心业务:用户" + username + "登录");
return "登录成功";
}
}
3. 定义日志切面(Aspect)
@Aspect
@Component
public class LogAspect {
// 切点:匹配UserService下的所有方法
@Pointcut("execution(* com.example.service.UserService.*(..))")
public void logPointcut() {}
// 前置通知:方法执行前打印入参
@Before("logPointcut()")
public void beforeLog(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("【前置日志】方法:" + methodName + ",入参:" + Arrays.toString(args));
}
// 后置通知:方法执行后打印返回值
@AfterReturning(value = "logPointcut()", returning = "result")
public void afterReturningLog(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("【后置日志】方法:" + methodName + ",返回值:" + result);
}
}
4. 测试运行
@SpringBootTest
public class AopTest {
@Autowired
private UserService userService;
@Test
public void testLogin() {
userService.login("zhangsan", "123456");
}
}
5. 运行结果
【前置日志】方法:login,入参:[zhangsan, 123456]
执行核心业务:用户zhangsan登录
【后置日志】方法:login,返回值:登录成功
完美实现了:不用修改 UserService 的源码,就给 login 方法加上了日志增强,完全符合 AOP 的设计思想。
六、Spring AOP 的常见应用场景
在实际开发中,AOP 的应用非常广泛,最常见的场景有:
- 日志记录:统一打印接口入参、返回值、耗时,排查问题
- 事务管理:Spring 的
@Transactional注解,底层就是 AOP 实现的事务切面 - 权限校验:统一校验用户接口权限,不用在每个业务方法里写权限代码
- 缓存处理:统一给查询方法加缓存,减少数据库压力
- 异常处理:统一捕获业务异常,封装返回结果
- 接口限流:统一给接口加限流规则,防止系统被打垮
七、总结
Spring AOP 是 Spring 框架的核心利器,核心价值就是解耦核心业务与通用横切逻辑,让代码更简洁、更易维护。
我们用一句话总结全文:
AOP 通过切面封装通用逻辑,用切点筛选目标方法,通过运行时动态代理生成代理对象,将通知逻辑织入目标方法,在不修改核心业务源码的前提下,实现系统能力的增强。
更多推荐

所有评论(0)