下面提供一份系统、可直接用于学习或面试的 Spring AOP 详解。内容覆盖核心概念、底层原理、常用注解、执行流程、实现方式以及实战示例,适合你直接应用到项目或文档中。


一、什么是 Spring AOP

**AOP(Aspect Oriented Programming,面向切面编程)**是对 OOP 的一种补充。

  • OOP 关注的是业务对象(类与方法)。
  • AOP 关注的是系统的横切逻辑(日志、事务、权限、监控等)。

AOP 能将这些“横切关注点”从业务逻辑中抽离出来,实现统一管理。


二、Spring AOP 的核心概念

概念解释
Aspect(切面)一个横切关注点(如日志切面、事务切面)。
JoinPoint(连接点)代码中可插入切面逻辑的点(Spring 中是方法执行)。
Pointcut(切点)决定在哪些方法上织入切面。
Advice(通知)在切点位置执行的动作,如前置、后置、环绕等。
Weaving(织入)将切面逻辑应用到目标对象的过程。
Proxy(代理对象)织入切面后生成的代理对象,调用它会触发切面逻辑。

三、Spring AOP 的通知类型(Advice)

Spring AOP 提供五种通知:

  1. @Before
    在目标方法执行前执行。
  2. @After
    无论方法是否异常都会执行(类似 finally)。
  3. @AfterReturning
    方法正常返回后执行。
  4. @AfterThrowing
    方法抛出异常后执行。
  5. @Around
    包裹整个方法执行,可手动控制方法执行时机、返回值、异常等。
    是最强大的通知类型。

四、切点表达式(Pointcut Expression)

最常用语法:

execution(返回值 包路径.类名.方法名(参数))

示例:

@Pointcut("execution(* com.example.service.*.*(..))")

表示拦截 com.example.service 包下的所有类的所有方法。

其他常用示例:

描述表达式
拦截某个类所有方法execution(* com.demo.UserService.*(..))
拦截所有 set 开头方法execution(* set*(..))
拦截某注解的方法@annotation(com.demo.Log)
拦截某注解的类@within(com.demo.Log)

五、Spring AOP 底层实现原理

Spring AOP 并不是靠字节码插桩,而是依靠动态代理技术

情况一:如果目标类实现了接口

Spring 使用 JDK 动态代理

  • Proxy.newProxyInstance()
  • 代理对象和目标对象共享接口

情况二:目标类没有实现接口

Spring 使用 CGLIB 动态代理

  • 基于 ASM 技术生成目标类的子类
  • 重写目标方法插入切面逻辑

SpringBoot 默认使用 CGLIB(只要使用 @Configuration 等)。


六、AOP 执行流程(Spring IOC + AOP 整合)

  1. 容器启动时扫描切面(Aspect 类)
  2. 解析切点表达式并保存
  3. 使用 BeanPostProcessor(如 AnnotationAwareAspectJAutoProxyCreator
    在 Bean 初始化后判断是否需要代理
  4. 如果匹配切点 → 创建代理对象
  5. 调用方法时 → 进入代理逻辑 → 执行增强 → 调用目标方法 → 返回结果

AOP 的核心是:
容器返回的不是原始 Bean,而是代理 Bean。


七、实战示例:日志切面

1. 添加依赖(Spring Boot 已默认包含 AOP)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 创建切面类

@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(* com.demo.service.*.*(..))")
    public void serviceMethods() {}

    @Before("serviceMethods()")
    public void before(JoinPoint joinPoint) {
        System.out.println("Before: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(value = "serviceMethods()", returning = "result")
    public void afterReturning(JoinPoint jp, Object result) {
        System.out.println("Return: " + result);
    }

    @AfterThrowing(value = "serviceMethods()", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("Exception: " + ex.getMessage());
    }

    @Around("serviceMethods()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Around before");
        Object ret = pjp.proceed();
        System.out.println("Around after");
        return ret;
    }
}


八、@Around 的核心增强逻辑

@Around("serviceMethods()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    long start = System.currentTimeMillis();

    try {
        // 执行目标方法
        Object result = pjp.proceed();
        System.out.println("耗时: " + (System.currentTimeMillis() - start));
        return result;
    } catch (Exception e) {
        System.out.println("错误日志: " + e.getMessage());
        throw e;
    }
}

这是用 AOP 实现 统一日志、异常、耗时统计 的企业应用最常见写法。


九、Spring AOP vs AspectJ

特性Spring AOPAspectJ
代理方式动态代理(运行时)编译期/类加载期织入
性能略慢
支持的 JoinPoint只有方法方法、构造器、字段访问等
使用难度简单较高
场景业务增强、日志、事务深度 AOP、监控工具、SDK

Spring AOP 足以满足大部分企业开发。


十、Spring AOP 最经典的应用场景

  1. 日志记录(请求日志、入参出参)
  2. 统一异常处理(拦截 Service 异常)
  3. 权限校验
  4. 接口限流
  5. 接口幂等性校验
  6. 事务管理(@Transactional 就是 AOP 实现)
  7. 性能监控 / 慢查询报警

如果你需要,我还可以进一步提供:

  • AOP 事务底层原理解析(@Transactional 源码剖析)
  • AOP 在 SpringBoot 项目中的最佳实践
  • AOP 的常见 Bug 与坑(必看)
  • AOP + 注解实现统一日志的完整可运行示例代码

告诉我你的下一步需求即可。