🚀 立即体验AI助手:2026-04-10 Spring AOP 核心概念与底层原理实战

小编头像

小编

管理员

发布于:2026年05月13日

12 阅读 · 0 评论

作为一名开发者,你是否曾为每个业务方法都要手动添加权限校验、日志打印、性能监控而感到烦恼?在一个订单系统中,新增、修改、删除、查询等每个方法都需要记录操作日志,如果每个方法都手动写一遍 log.info(),不仅代码重复臃肿,更让维护成本急剧上升。立即体验AI助手,它能够快速生成高质量的代码解决方案,帮助开发者更好地理解类似 AOP 这样的核心编程思想如何从根本上解决这类问题。今天,我们就来深入讲解 Spring 框架中的核心功能——AOP(Aspect Oriented Programming,面向切面编程),系统梳理其核心概念、实现原理以及面试中的高频考点。


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

先看一段典型的业务代码:

java
复制
下载
@PostMapping("/delete")

public BaseResponse deleteApp(long id) { User user = checkPermission(); // 重复代码1 if (!user.isAdmin()) { // 重复代码2 throw new BusinessException(ErrorCode.NO_AUTH_ERROR); } log.info("开始删除应用,id=" + id); // 重复代码3 long start = System.currentTimeMillis(); // 真正的业务逻辑... appService.delete(id); long end = System.currentTimeMillis(); log.info("删除耗时:" + (end - start) + "ms"); return BaseResponse.success(); } @PostMapping("/update") public BaseResponse updateApp(App app) { User user = checkPermission(); // 同样重复 if (!user.isAdmin()) { throw new BusinessException(ErrorCode.NO_AUTH_ERROR); } log.info("开始更新应用"); // 真正的业务逻辑... }

这段代码存在三大痛点:

  1. 代码重复严重:权限校验、日志记录、性能监控在每个方法中反复出现

  2. 耦合度过高:业务逻辑与横切关注点(权限、日志)混杂在一起

  3. 维护成本高:若要修改权限校验规则,需要改动所有相关方法

AOP(面向切面编程)正是为解决这些问题而生。它将日志、安全、事务等横切关注点从业务逻辑中剥离,显著提升代码的模块化程度-

二、核心概念详解

概念 A:AOP 标准定义

AOP(Aspect Oriented Programming,面向切面编程) 是一种编程范式,通过将横切关注点与核心业务逻辑解耦,在不修改原有业务代码的前提下,对方法进行增强,统一处理日志、事务、权限、监控等横切逻辑-1

生活化类比:想象一个小区的安保系统-2

  • 小区 = 整个应用程序

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

  • 大门 = 方法入口

  • 保安 = 切面(Aspect)

  • 访客规则 = 切入点表达式(Pointcut)

  • 检查流程 = 通知(Advice)

保安(切面)的工作是:按照规则(切入点)对进入大门(连接点)的人进行检查(通知),而住户(目标对象)完全不需要关心安保逻辑。

概念 B:七大核心术语

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

-2

三、概念关系与区别总结

用一句话理清它们的逻辑关系:

切面(Aspect) 通过 切入点(Pointcut) 筛选 连接点(Join Point) ,在 织入(Weaving) 时将 通知(Advice) 应用到 目标对象(Target) 上。

核心区分要点:

  • 连接点 vs 切入点:连接点是所有可拦截的候选方法,切入点是筛选后真正需要增强的那些方法-2

  • 切面 vs 通知:切面是模块的整体,通知是具体在何时执行的增强动作-1

四、代码示例实战

4.1 添加依赖

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

4.2 方式一:通过 execution 表达式配置

java
复制
下载
@Component
@Aspect
public class PerformanceAspect {
    
    @Around("execution( com.example.service.impl..(..))")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        // ⭐ 调用原始业务方法
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info("【{}】执行耗时: {}ms", joinPoint.getSignature().getName(), (end - begin));
        return result;
    }
}

-1

4.3 方式二:通过自定义注解配置

首先定义权限校验注解:

java
复制
下载
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthCheck {
    String mustRole() default "admin";
}

然后编写切面类:

java
复制
下载
@Component
@Aspect
public class AuthInterceptor {
    
    @Around("@annotation(authCheck)")
    public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) 
            throws Throwable {
        // 前置增强:权限校验
        User currentUser = UserContext.getCurrentUser();
        if (currentUser == null || !currentUser.getRole().equals(authCheck.mustRole())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        // 执行目标方法
        return joinPoint.proceed();
    }
}

4.4 对比展示

没有AOP时:每个业务方法都包含重复的权限校验代码
使用AOP后:业务代码只关心核心逻辑

java
复制
下载
@PostMapping("/delete")
@AuthCheck(mustRole = "admin")  // 仅一行注解
public BaseResponse deleteApp(long id) {
    // 只写真正的业务逻辑...
    appService.delete(id);
    return BaseResponse.success();
}

-2

4.5 五种通知类型

通知类型执行时机使用场景
@Before目标方法执行之前权限预检、参数校验
@After目标方法执行之后(无论是否异常)资源释放、清理操作
@AfterReturning目标方法正常返回后日志记录、返回值处理
@AfterThrowing目标方法抛出异常时异常监控、告警通知
@Around环绕目标方法(功能最强)性能监控、事务管理、参数修改

-1

关键说明@Around 是最强大的通知类型,能够精确控制方法执行的全过程,必须调用 joinPoint.proceed() 来执行原始业务方法,且返回值需指定为 Object 类型-1。若需要获取返回值或捕获异常,务必使用 @Around,因为 @Before 无法获取返回结果,@AfterReturning 无法捕获异常信息-8

五、底层原理:动态代理

5.1 核心原理

Spring AOP 的底层本质是动态代理:用动态代理包装原始 Bean,让方法执行过程被增强-27。最终生成一个代理对象,调用方法时先走代理逻辑,再走原方法,从而实现增强-

5.2 JDK 动态代理 vs CGLIB

Spring AOP 根据目标类是否实现接口,自动选择不同的动态代理技术:

对比项JDK 动态代理CGLIB
代理方式接口代理子类代理
是否依赖接口必须有接口不需要接口
调用性能调用成本低生成类成本高,调用快
能否代理 final 方法❌ 不可❌ 也不可
依赖Java 原生,无需额外依赖需引入 CGLIB 库
代理类命名$Proxy0 格式Service$$EnhancerBySpringCGLIB

-27
-26

5.3 Spring 的默认策略

  • Spring Framework 默认:优先使用 JDK 动态代理,当目标类没有实现接口时自动切换为 CGLIB-

  • Spring Boot 2.x+ 默认:将默认值改为了 CGLIB-

  • 可通过 @EnableAspectJAutoProxy(proxyTargetClass = true) 强制使用 CGLIB-28

5.4 底层依赖的关键技术

Spring AOP 底层依赖两大核心技术:

  1. 反射(Reflection) :JDK 动态代理的核心,运行时获取方法元信息并调用

  2. 字节码生成(Bytecode Generation) :CGLIB 基于 ASM 字节码技术,动态生成目标类的子类-26

Spring 通过 BeanPostProcessor 机制,在 Bean 初始化阶段创建代理对象,而非在容器启动时立即创建-27

六、高频面试题与参考答案

面试题1:什么是 Spring AOP?它的核心概念有哪些?

标准答案

AOP(Aspect Oriented Programming,面向切面编程)是一种编程范式,通过将横切关注点(如日志、事务、权限)从业务逻辑中剥离,实现代码解耦。Spring AOP 的核心概念包括:

  1. 切面(Aspect) :横切关注点的模块化

  2. 连接点(Join Point) :可被拦截的方法执行点

  3. 切入点(Pointcut) :筛选连接点的匹配规则

  4. 通知(Advice) :在切入点执行的增强逻辑,包含 @Before、@After、@AfterReturning、@AfterThrowing、@Around 五种类型

  5. 目标对象(Target) :被增强的业务对象

  6. 织入(Weaving) :将切面应用到目标对象的过程

-2
-1

面试题2:Spring AOP 的实现原理是什么?JDK 动态代理和 CGLIB 有什么区别?

标准答案

Spring AOP 的核心原理是动态代理,运行时动态生成代理对象,在目标方法前后织入增强逻辑-20

JDK 动态代理CGLIB 的核心区别:

区别点JDK 动态代理CGLIB
代理方式基于接口基于子类继承
依赖条件目标类必须有接口无需接口,但不能是 final 类
性能反射调用,调用开销小字节码生成,调用速度快
依赖Java 原生,无额外依赖需引入 CGLIB 库

Spring 默认优先使用 JDK 动态代理,目标类无接口时自动切换为 CGLIB。Spring Boot 2.x 起将默认改为 CGLIB。

-27
-26

面试题3:@Around 通知和其他通知类型的区别是什么?为什么推荐用 @Around 处理操作日志?

标准答案

@Around 是功能最强的通知类型,能够精确控制方法执行的全过程,其他四种通知只能在特定时机执行。

推荐用 @Around 处理操作日志,原因如下:

  • @Before 拿不到方法返回结果

  • @AfterReturning 捕获不到异常信息

  • @AfterThrowing 拿不到正常返回值

  • 只有 @Around 能通过 proceed() 方法统一获取返回值、捕获异常、精确计算耗时

-8
-1

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

标准答案

Spring AOP 和 AspectJ 都是 Java 中实现 AOP 的框架,但定位完全不同-37

  • Spring AOP:Spring 框架自带的轻量级 AOP 实现,只支持运行时代理,底层使用 JDK 动态代理或 CGLIB,只能拦截 Spring 容器管理的 Bean 方法。优点是简单、零配置成本。

  • AspectJ:功能完整的 AOP 框架,支持编译时、类加载时、运行时三种织入方式,能拦截构造函数、静态方法、字段访问等更多类型的连接点。功能更强大但配置更复杂。

七、结尾总结

核心知识点回顾

  1. AOP 的价值:将横切关注点从业务逻辑中剥离,消除重复代码,降低耦合度

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

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

  4. 底层原理:动态代理(JDK 代理 + CGLIB),依赖反射和字节码生成技术

  5. 面试关键点:能说清动态代理的选择策略及两种代理方式的区别

易错点提醒

⚠️ 常见误区

  • 切面类必须被 Spring 容器管理(添加 @Component),否则 AOP 不会生效-28

  • @Around 通知必须调用 proceed() 且只能调用一次

  • CGLIB 无法代理 final 类或 final/static/private 方法-28

  • 自定义注解必须声明 @Retention(RetentionPolicy.RUNTIME),否则运行期无法读取-8

下一篇我们将深入讲解 Spring 事务管理的实现原理,敬请关注!

标签:

相关阅读