Spring AOP 2026最新详解:核心概念+代码实战+面试要点

小编头像

小编

管理员

发布于:2026年04月28日

14 阅读 · 0 评论

更新时间:2026年4月10日

Spring AOP(面向切面编程)是Spring框架的两大核心支柱之一,与IoC(控制反转)共同构成了整个Spring生态的底层基石。但在日常开发中,不少开发者对AOP的理解仍停留在“用注解做日志或事务”的表面,一旦遇到切面失效、代理选择不当等问题就束手无策。本文由随牛ai助手为你系统梳理Spring AOP的核心概念、底层原理、实战代码与高频面试题,帮你从“会用”进阶到“懂原理、能排错”。

一、痛点切入:为什么需要AOP?

先看一段没有使用AOP的代码:

java
复制
下载
// ❌ 没有切面:每个方法都要写重复的权限校验
@PostMapping("/delete")
public BaseResponse deleteApp(long id) {
    User user = checkPermission();           // 重复代码1
    if (!user.isAdmin()) {                   // 重复代码2
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    }
    // 真正的业务逻辑...
}

@PostMapping("/update")
public BaseResponse updateApp(App app) {
    User user = checkPermission();           // 重复代码1
    if (!user.isAdmin()) {                   // 重复代码2
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    }
    // 真正的业务逻辑...
}

以上代码存在三个明显问题:

  • 代码冗余:权限校验、日志记录等逻辑在每个方法中重复出现;

  • 耦合度高:业务代码与非业务逻辑(权限、日志、事务)混杂在一起;

  • 维护困难:修改权限规则时,需要改遍所有相关方法。

AOP正是为解决这些问题而生。AOP全称 Aspect Oriented Programming(面向切面编程),它允许你将日志、事务、权限校验等横切关注点从业务逻辑中剥离,在不修改原有业务代码的前提下,对方法进行统一增强-3

text
复制
下载
// ✅ 有切面:业务代码只关心业务
@PostMapping("/delete")
@AuthCheck(mustRole = "admin")
public BaseResponse deleteApp(long id) {
    // 真正的业务逻辑...
}

二、核心概念详解:AOP的七大术语

AOP涉及七个核心概念,理解它们是掌握AOP的第一步-2-4

概念(中)概念(英)说明代码示例
切面Aspect横切关注点的模块化(把通用功能抽离出来)@Aspect标注的类
连接点Join Point可以被拦截的方法执行点Controller/Service中所有方法
切入点Pointcut真正需要被拦截的连接点(筛选条件)@annotation(authCheck)
通知/增强Advice在切入点执行的逻辑切面类中的方法
目标对象Target被代理的对象标注了@AuthCheck的方法所在的类
织入Weaving将切面应用到目标对象的过程Spring运行时自动完成
引入Introduction动态添加方法或字段(不常用)-

生活案例助你理解:小区门禁系统

想象一个小区的安保系统-2

  • 小区 = 整个应用程序

  • 每家每户 = 各个业务类(Controller、Service)

  • 大门 = 方法入口

  • 保安 = 切面(Aspect)

  • 访客规则 = 切入点(Pointcut) ——只检查没有门禁卡的外卖员

  • 检查流程 = 通知(Advice) ——登记信息、联系业主、决定是否放行

  • 住户 = 目标对象(Target)

  • 进入大门的时刻 = 连接点(Join Point)

五种通知类型详解

通知类型注解执行时机典型应用场景
前置通知@Before方法执行之前参数校验、日志记录
后置返回通知@AfterReturning方法正常返回之后结果处理、返回值封装
异常通知@AfterThrowing方法抛出异常时异常监控、告警
最终通知@After方法执行完成之后(类似finally)资源释放、清理工作
环绕通知@Around方法执行前后(最强大)权限校验、性能监控、事务管理

执行顺序

正常执行流程

text
复制
下载
@Around 前置处理 → @Before → 执行原方法 → @AfterReturning → @After → @Around 后置处理

异常执行流程

text
复制
下载
@Around 前置处理 → @Before → 执行原方法(抛出异常)→ @AfterThrowing → @After → @Around 捕获异常

三、AOP与IoC:两大支柱的关系

IoC(Inversion of Control,控制反转)AOP 是Spring框架的两大核心支柱-

  • IoC:将对象的创建和管理交由Spring容器负责,降低对象之间的耦合度。

  • AOP:在运行时动态地为对象添加横切逻辑,增强功能。

两者的关系可以概括为:IoC负责“对象从哪来”,AOP负责“对象怎么增强” 。Spring IoC容器不依赖AOP,但二者结合使用构成了强大的中间件解决方案-

简单来说:IoC让Spring来管理对象,AOP让Spring来增强对象。业务代码不再需要手动new对象(IoC),也不再需要到处复制粘贴权限校验代码(AOP)。

四、代码实战:从零实现一个AOP切面

4.1 添加依赖

pom.xml中添加Spring Boot AOP起步依赖:

xml
复制
下载
运行
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

4.2 定义自定义注解(可选)

java
复制
下载
import java.lang.annotation.;

@Target(ElementType.METHOD)      // 作用在方法上
@Retention(RetentionPolicy.RUNTIME)  // 运行时保留
public @interface LogAnnotation {
    String value() default "";
}

4.3 编写切面类

java
复制
下载
@Aspect                    // 声明这是一个切面
@Component                 // 交给Spring管理
@Slf4j
public class LogAspect {
    
    // 环绕通知:匹配标注了@LogAnnotation的方法
    @Around("@annotation(logAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) 
            throws Throwable {
        
        long startTime = System.currentTimeMillis();
        
        try {
            // @Before 的逻辑
            log.info("开始执行方法: {}", joinPoint.getSignature().getName());
            log.info("注解参数: {}", logAnnotation.value());
            
            // 执行原方法(核心!)
            Object result = joinPoint.proceed();
            
            // @AfterReturning 的逻辑
            long endTime = System.currentTimeMillis();
            log.info("方法执行成功,耗时: {}ms", endTime - startTime);
            return result;
            
        } catch (Throwable e) {
            // @AfterThrowing 的逻辑
            log.error("方法执行失败: {}", e.getMessage(), e);
            throw e;
        } finally {
            // @After 的逻辑
            log.info("方法执行完成");
        }
    }
}

4.4 使用切面

java
复制
下载
@Service
public class UserService {
    
    @LogAnnotation("用户注册操作")
    public void register(String username) {
        System.out.println("执行注册业务逻辑...");
    }
}

关键要点

  • @Around环绕通知需要手动调用joinPoint.proceed()来执行原方法-3

  • 其他通知(@Before@After等)不需要手动调用目标方法;

  • 切面类必须放在启动类的包或子包下,否则需要手动配置@ComponentScan-3

五、底层原理:动态代理机制

Spring AOP的底层实现基于 动态代理 技术-26

5.1 JDK动态代理 vs CGLIB

对比维度JDK动态代理CGLIB
代理方式接口代理子类代理
是否依赖接口必须有接口不需要接口
性能反射调用,开销略高基于字节码,调用更快
final方法/类不涉及无法代理(无法继承/重写)
Spring默认选择有接口时使用无接口时使用

5.2 Spring的选择策略

Spring AOP的选择逻辑--27

java
复制
下载
if (hasUserSuppliedProxyInterfaces()) {
    return JDK动态代理;
} else {
    return CGLIB代理;
}
  • 当目标类实现了接口时,默认使用JDK动态代理;

  • 当目标类没有实现接口时,使用CGLIB代理;

  • 可通过spring.aop.proxy-target-class=true强制使用CGLIB。

5.3 核心机制流程

  1. 代理创建时机:在Bean初始化完成后,通过BeanPostProcessorpostProcessAfterInitialization方法创建代理对象并替换原始Bean-27

  2. 方法调用链路:客户端调用方法 → 代理对象拦截 → 执行拦截器链(MethodInterceptor)→ 依次执行各通知逻辑 → 最终调用目标方法。

六、高频面试题

面试题1:什么是AOP?它解决了什么问题?

参考答案
AOP(Aspect Oriented Programming,面向切面编程)是一种编程范式,通过横向抽取机制将日志、事务、权限等横切关注点从业务逻辑中分离出来,在不修改原有业务代码的前提下实现统一增强,解决了OOP在处理跨模块通用功能时产生的代码冗余和高耦合问题-37

踩分点:定义 + 横切关注点 + 不修改原代码 + 与OOP的关系

面试题2:Spring AOP底层是如何实现的?JDK和CGLIB的区别是什么?

参考答案
Spring AOP基于动态代理实现。代理方式取决于目标类是否实现接口:有接口时默认用JDK动态代理(基于java.lang.reflect.Proxy),无接口时用CGLIB(基于子类字节码生成)。JDK要求目标类必须实现接口,CGLIB则不需要;CGLIB性能通常更高,但无法代理final类和方法-35

踩分点:动态代理 + JDK vs CGLIB对比 + Spring选择策略

面试题3:Spring AOP和AspectJ有什么区别?

参考答案
Spring AOP是Spring框架自带的轻量级AOP实现,仅支持运行时动态代理织入,只能拦截Spring容器管理的Bean方法,功能足够覆盖大多数业务场景。AspectJ是功能完整的AOP框架,支持编译时和类加载时织入,功能更强大但配置复杂。Spring AOP默认使用AspectJ的注解语法-37

踩分点:运行时 vs 编译时 + 功能范围 + 配置复杂度

面试题4:为什么@Transactional有时会失效?

参考答案
最常见的原因有三个:

  1. 方法不是public的——AOP默认只拦截public方法;

  2. 同一个类内部调用(this.methodB())——调用未经过代理对象,直接走this引用;

  3. final方法或final类无法被CGLIB代理-37

踩分点:public限制 + 内部自调用 + final限制

面试题5:@Around@Before/@After有什么区别?

参考答案
@Before@After只在方法执行前后插入逻辑,无法控制目标方法的执行。@Around是最强大的通知类型,通过ProceedingJoinPoint.proceed()可以完全控制目标方法的执行流程,包括决定是否执行、修改返回值、捕获异常等,权限校验和性能监控通常使用@Around实现-37

踩分点:控制能力对比 + proceed方法 + 适用场景

七、总结与易错点

核心知识回顾

  1. AOP是一种编程思想,与OOP互补而非替代,专注于横向抽取横切关注点;

  2. 七大核心概念:切面、连接点、切入点、通知、目标对象、织入、引入;

  3. 五种通知类型@Before@AfterReturning@AfterThrowing@After@Around

  4. 底层原理:JDK动态代理(接口) + CGLIB动态代理(子类);

  5. AOP失效的三大原因:非public方法、内部自调用、final限制。

常见易错点提醒

  • 注意@Around环绕通知必须手动调用proceed()方法,否则原业务逻辑不会执行;

  • 注意:切面类必须标注@Aspect@Component,且位于启动类扫描范围内;

  • 注意:切入点表达式越精确越好,避免不必要的性能开销;

  • 注意:多个切面可以通过@Order控制执行顺序;

  • 注意:内部方法自调用不会触发AOP增强,需要获取代理对象后再调用。


本文由随牛ai助手为你整理,下一篇将深入AOP代理机制源码级解析,敬请关注!

标签:

相关阅读