AI助手小汪温馨提示:北京时间2026年4月10日,Spring AOP依然是面试中的高频必考项,也是企业级开发的核心支柱。本文将带你在最短时间内打通从概念到原理、从代码到面试的完整链路。
在Spring框架的技术体系中,AOP(Aspect-Oriented Programming,面向切面编程)与IoC并称为两大核心支柱,是每个Java开发者绕不开的必修课-。但在实际学习中,很多同学面临一个共同的痛点:@Transactional加上了,为什么事务没生效?代码照着教程写,日志切面就是不执行?面试官一问“Spring AOP底层原理”,就只能吞吞吐吐说“好像是用代理”…… -32

本文将从“为什么要用AOP”出发,逐步深入核心概念、代码实战、底层原理和面试考点,帮你建立起完整的知识链路。全程由AI助手小汪陪伴,拒绝晦涩理论,多对比、多示例、多考点,让你看完就能用、面试答得出。
本文基于Spring Boot 3.x + Spring 6.x(2026主流版本),源码环境JDK 17+。

一、痛点切入:为什么代码里到处都是重复逻辑?
先看一段“反面教材”。假设我们要在Service层的每个方法前后都加上日志记录:
public class UserService { public void createUser(String username) { System.out.println("【开始日志】调用createUser"); // 核心业务:创建用户... System.out.println("【结束日志】createUser执行完成"); } public void deleteUser(Long userId) { System.out.println("【开始日志】调用deleteUser"); // 核心业务:删除用户... System.out.println("【结束日志】deleteUser执行完成"); } // 如果有50个方法,每个都要重复写两行日志代码... }
这段代码暴露了三个典型问题:
耦合高:日志代码侵入到业务方法内部,核心逻辑与辅助功能混在一起;
扩展性差:如果想换个日志框架,几十个类每个都要改一遍;
代码冗余:同样的日志代码在N个方法中重复出现。
AOP就是为解决这个问题而生的——它允许你把日志、事务、权限校验这类“横切关注点”抽离成独立的模块(切面),在不修改业务代码的前提下统一添加功能-1。
二、核心概念讲解:什么是AOP?
AOP,全称Aspect-Oriented Programming(面向切面编程),是一种编程范式,它通过在运行期动态代理,将横切关注点与主业务逻辑分离,实现程序的统一维护-13。
简单说:OOP是纵向继承/封装,AOP是横向切入-1。
为了方便记忆,AI助手小汪用“快递员送件”来打比方:
| 概念 | 英文 | 快递员类比 | 代码对应 |
|---|---|---|---|
| 切面 | Aspect | 你定义的一套完整增强规则(如“所有包裹都要扫码”) | 用@Aspect标记的类 |
| 连接点 | Join Point | 快递员送件过程中可以“插入动作”的所有环节(取件前/送达后/签收时) | 业务方法执行 |
| 切点 | Pointcut | 精确匹配“哪些包裹需要扫码”(如只针对“省外件”) | 切入点表达式 |
| 通知 | Advice | 在切点上执行的增强动作,如“取件前拍照” | @Before / @After / @Around |
| 代理 | Proxy | 快递公司包装后的“增强版快递员” | JDK/CGLIB生成的代理对象 |
| 织入 | Weaving | 将增强动作注入到目标方法执行链路的过程 | 运行时织入-1 |
Spring AOP中常用的5种通知类型如下:
@Before:目标方法执行前触发;
@AfterReturning:目标方法正常返回后触发;
@AfterThrowing:目标方法抛出异常后触发;
@After:无论正常还是异常,最终都会触发(类似
finally);@Around:包裹整个方法,可控制是否执行、获取参数、修改返回值(最强大)-13。
三、关联概念讲解:Spring AOP与AspectJ
AspectJ是Java生态中最完整、最强大的AOP框架,它支持编译时织入和类加载时织入,功能远超Spring AOP(如支持构造器拦截、字段拦截等)-53。
而Spring AOP是Spring框架对AOP思想的实现,它选择了运行时动态代理的方式,功能虽不如AspectJ全面,但胜在轻量、易用、与Spring IoC无缝集成,足以覆盖99%的业务场景-1。
两者关系一句话概括:AOP是一种编程思想,Spring AOP是一种运行时实现,AspectJ是一种编译时实现。Spring AOP借用了AspectJ的注解语法(如@Aspect、@Pointcut)和切入点表达式语言,但底层实现完全不同。
四、代码实战:在Spring Boot中用AOP实现日志监控
Step 1:添加依赖
<!-- Maven:Spring Boot Starter AOP 已包含自动配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
Step 2:编写切面类
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // Step 2.1:定义切入点(匹配com.example.service包下所有类的所有方法) @Pointcut("execution( com.example.service..(..))") public void serviceLayer() {} // Step 2.2:前置通知——方法执行前记录 @Before("serviceLayer()") public void logBefore(JoinPoint joinPoint) { System.out.println("[AOP] 执行方法: " + joinPoint.getSignature().getName()); } // Step 2.3:环绕通知——统计执行耗时(最常用) @Around("serviceLayer()") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); // ⭐ 执行目标方法 long elapsed = System.currentTimeMillis() - start; System.out.println("[AOP] " + joinPoint.getSignature().getName() + " 耗时: " + elapsed + "ms"); return result; } }
执行流程解析:当调用userService.createUser()时,Spring容器实际注入的是代理对象而非原始对象。代理对象拦截方法调用,依次执行@Before → @Around(前半部分)→ joinPoint.proceed()调用原始方法 → @Around(后半部分)→ @After → @AfterReturning,最终返回结果-41。
五、底层原理:JDK动态代理 vs CGLIB
Spring AOP的底层本质是动态代理。根据目标类是否实现接口,Spring会自动选择不同的代理方式-21:
🔵 JDK动态代理(基于接口)
原理:运行时为目标接口生成代理类,通过
Proxy.newProxyInstance()+InvocationHandler.invoke()实现方法拦截-58;要求:目标类必须实现至少一个接口;
性能:JDK 9+版本后性能已大幅优化,与CGLIB差距缩小-58。
🔴 CGLIB(基于继承)
原理:通过ASM字节码技术生成目标类的子类,在子类中重写目标方法并插入增强逻辑-22;
要求:目标类不能是
final的,目标方法不能是final的;特点:创建代理对象时耗时约是JDK的8倍,但方法执行性能高约10倍,适合单例Bean-。
📌 版本差异速查:Spring Boot 2.0以前默认JDK代理(有接口时),Spring Boot 2.0+及Spring Framework 5+默认CGLIB代理,可通过spring.aop.proxy-target-class=false切换--1。
六、技术支撑:AOP的底层依赖
Spring AOP的实现离不开以下底层技术-22:
| 技术 | 作用 |
|---|---|
| 反射 | JDK动态代理通过Method.invoke()调用目标方法,是拦截逻辑的核心桥梁 |
| ASM字节码增强 | CGLIB通过ASM在运行时生成目标类的子类,实现无接口代理 |
| 责任链模式 | 当有多个通知(Advice)时,Spring通过ReflectiveMethodInvocation串联成链,按序执行 |
| BeanPostProcessor | Spring在Bean初始化后,通过AnnotationAwareAspectJAutoProxyCreator判断是否需要生成代理对象并替换原始Bean |
七、高频面试题与参考答案
⭐ 1. 什么是AOP?
标准答案:AOP(面向切面编程)是一种编程范式,它允许在不修改业务代码的情况下,为方法统一添加横切逻辑(如日志、事务、权限),通过动态代理在方法执行前后织入增强-32。
踩分点:提到了不修改代码、横切关注点、动态代理三个关键词。
⭐ 2. Spring AOP是如何实现的?JDK代理和CGLIB有什么区别?
标准答案:Spring AOP基于动态代理实现。有接口时优先使用JDK动态代理(基于反射+Proxy类),无接口时使用CGLIB(基于ASM生成子类)。CGLIB无法代理final类和final方法。Spring Boot 2.0+默认使用CGLIB-33-。
⭐ 3. @Transactional为什么会失效?列举常见场景。
标准答案:①方法不是public的;②在同一个类内部调用(未经过代理对象);③目标方法被声明为final;④异常被try-catch吞掉;⑤数据库引擎不支持事务-32。
⭐ 4. @Around和@Before/@After的核心区别是什么?
标准答案:@Around是最强大的通知,可以通过ProceedingJoinPoint.proceed()控制目标方法的执行时机、获取参数、修改返回值,甚至决定是否执行原方法;而@Before/@After只做前置/后置增强,无法控制方法执行本身-32。
⭐ 5. Spring AOP和AspectJ有什么区别?
标准答案:Spring AOP是运行时动态代理实现,轻量但功能有限(仅支持方法级拦截);AspectJ是编译时织入,功能更完整(支持字段拦截、构造器拦截等),但需要额外配置-32。
八、结尾总结
本文AI助手小汪带你系统梳理了Spring AOP的完整知识链路,要点回顾如下:
✅ 核心概念:Aspect(切面)+ Pointcut(切点)+ Advice(通知)= AOP三要素,底层依赖动态代理-1;
✅ 实现方式:JDK动态代理(基于接口)+ CGLIB(基于继承),Spring Boot 2.0+默认CGLIB;
✅ 实战关键:切面类加@Aspect+@Component,切入点用@Pointcut,通知用@Before/@Around等;
✅ 面试必考点:事务失效的常见原因、@Around与@Before的区别、JDK与CGLIB的选择逻辑;
✅ 易错点:内部方法调用不走代理(AOP失效)、final类/方法无法代理、通知执行顺序为@Around前半→@Before→目标方法→@Around后半→@After→@AfterReturning。
🔜 下一篇预告:AI助手小汪将继续带大家深入Spring事务传播机制,从@Transactional的7种传播行为到底层原理,敬请期待!
本文为AI助手小汪原创技术分享,首发于2026年4月10日。欢迎留言交流,如需转载请联系授权。