# AOP 详解

作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)
相关源码参考: Spring源码中文注释仓库5.3.x分支 (opens new window)


本章节重点拆解 Spring AOP 的初始化流程,涵盖从 @EnableAspectJAutoProxy 到代理对象创建,涉及方法调用时的拦截器链。

读者需要注意, 此处的JDK动态代理相关代码均为Spring框架封装, 不要混淆

# 开启注解驱动 AOP

@EnableAspectJAutoProxy 是开启注解驱动 AOP 的入口:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false; // 是否使用 CGLIB 代理
    boolean exposeProxy() default false;      // 是否允许 AopContext 获取代理
}
1
2
3
4
5
6
7
8
  • 作用:通过 @ImportAspectJAutoProxyRegistrar 导入容器,注册 AOP 基础设施 Bean。

  • 核心 BeanAnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor),负责扫描 @Aspect 并为符合条件的 Bean 创建代理。

# 核心注册流程

@EnableAspectJAutoProxy
   └─ @Import(AspectJAutoProxyRegistrar)

AspectJAutoProxyRegistrar.registerBeanDefinitions
   ├─ 注册 AOP 自动代理创建器
   │    └─ AnnotationAwareAspectJAutoProxyCreator (核心 BeanPostProcessor)
   │
   └─ 解析注解参数
        ├─ proxyTargetClass = true → 强制使用 CGLIB
        └─ exposeProxy = true → 允许通过 AopContext 获取当前代理
1
2
3
4
5
6
7
8
9
10

AnnotationAwareAspectJAutoProxyCreator 是 Spring AOP 的核心组件,负责扫描 @Aspect 注解并为符合条件的 Bean 创建代理对象。它是 AOP 代理生成的入口,但并非在普通 refresh() 扫描阶段注册,而是通过 ImportBeanDefinitionRegistrar 提前注册为基础设施 Bean。

# 关键类解析

AnnotationAwareAspectJAutoProxyCreator
  → AspectJAwareAdvisorAutoProxyCreator
  → AbstractAdvisorAutoProxyCreator
  → AbstractAutoProxyCreator
  → SmartInstantiationAwareBeanPostProcessor
  → BeanPostProcessor
1
2
3
4
5
6
  • 继承关系说明
    • 本质是 BeanPostProcessor 的一种
    • 作为基础设施 Bean 提前注册,不经过普通 Bean 扫描
  • 核心方法
    • AbstractAutoProxyCreator#postProcessBeforeInstantiation
      • 在 Bean 初始化后调用,用于判断是否需要生成代理对象, 实现 AOP 功能
  • 主要职责
    1. 扫描和解析 @Aspect 注解
    2. 构建对应的 Advisor
    3. 在 Bean 初始化完成后生成 JDK 或 CGLIB 代理对象
  • 特点
    • 提前注册的基础设施 Bean
    • 不经过普通 Bean 扫描逻辑
    • 为容器中的目标 Bean 提供 AOP 增强

# 触发 AOP 代理生成

Spring AOP 的代理生成逻辑可以拆成两个阶段:

  1. AAAPC (AnnotationAwareAspectJAutoProxyCreator) 注册与初始化

  2. 普通 Bean 初始化调用后置处理方法,判断是否需要创建代理

这样划分可以清楚地理解 @Aspect 扫描时机代理对象创建流程

# 1. AAAPC 注册与初始化

当开启注解驱动 AOP 时,@EnableAspectJAutoProxy 会通过 AspectJAutoProxyRegistrar 注册 AAAPC

@EnableAspectJAutoProxy
   └─ @Import(AspectJAutoProxyRegistrar)
         └─ registerBeanDefinitions()
               └─ AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
1
2
3
4
  • AAAPC 是 BeanPostProcessor 类型的基础设施 Bean
  • 它会被提前注册到容器,不经过普通 Bean 扫描
  • Spring 容器刷新时实例化 AAAPC:
finishBeanFactoryInitialization(beanFactory)
└─ preInstantiateSingletons()
     └─ getBean("annotationAwareAspectJAutoProxyCreator")
           └─ createBean → doCreateBean → 实例化 AAAPC
1
2
3
4

重点:

  • AAAPC 初始化自身时,并不立即扫描 @Aspect Bean
  • 它在实例化完成后就具备了为后续目标 Bean 创建代理的能力。

# 2. 普通 Bean 初始化触发代理创建

普通 Bean 初始化时,会调用 AAAPC 的 postProcessAfterInitialization 方法:

applyBeanPostProcessorsAfterInitialization(existingBean, beanName)
└─ 遍历所有 BeanPostProcessor
     └─ 调用 postProcessAfterInitialization(result, beanName)
          └─ AnnotationAwareAspectJAutoProxyCreator.wrapIfNecessary(bean, beanName)
1
2
3
4

关键逻辑:

  1. 普通 Bean 首次初始化时, 扫描 @Aspect → 全局 Advisor 缓存

    • 当 AAAPC 初始化或首次处理 Bean 时,会扫描容器中所有 @Aspect Bean。
    • 每个切面类的每个切点方法会生成一个或多个 Advisor
    • 这些 Advisor 会被添加到 AAAPC 内部缓存,这个缓存是 全局可复用
      • advisorsCache(缓存 Advisor 列表)
      • aspectFactoryCache(缓存切面实例工厂)
    • 此时并不会判断某个 Bean 是否匹配,只是先把所有切面方法都生成对应 Advisor。

    ⚠️ 这个阶段的作用:把所有切面方法转成 Advisor,并缓存起来

  2. Bean 初始化 → 为当前 Bean 生成代理对象

    • 当普通 Bean 初始化完成后,AAAPC 的 postProcessAfterInitialization 会被调用。

      1. 获取全局 Advisor 缓存

        • AAAPC 拿到所有已生成的 Advisor(上一步缓存的列表)。
      2. 类级别匹配

        • 调用 findAdvisorsThatCanApply(candidateAdvisors, beanClass)

        • 只有匹配当前 Bean 的 Advisor 才会被选中。

      3. 生成代理对象

        • 创建 ProxyFactory 或 CGLIB 代理

        • 将匹配的 Advisor 添加到该 Bean 的 AdvisedSupport.advisors[]

        • 返回代理对象替换原 Bean

    ⚠️ 这个阶段的作用:每个 Bean 的代理对象只保存自己匹配的 Advisor,方法调用时再根据切点生成拦截器链。

# 3. 源码解析

# 1. AbstractAutoProxyCreator 详解

AnnotationAwareAspectJAutoProxyCreator 继承自 AbstractAutoProxyCreator,主要通过 wrapIfNecessarycreateProxy 完成代理包装:

postProcessAfterInitialization(bean, beanName)
└─ wrapIfNecessary(bean, beanName, cacheKey)
      │
      ├─ 判断基础设施类 / targetSourcedBeans → 返回原 Bean
      ├─ 检查 advisedBeans 缓存
      ├─ 获取增强器 → getAdvicesAndAdvisorsForBean(beanClass, beanName)
      │     └─ findEligibleAdvisors(beanClass, beanName)
      │           ├─ findCandidateAdvisors() → 全局缓存的 Advisor(首次扫描生成)
      │           ├─ findAdvisorsThatCanApply(candidateAdvisors, beanClass) → 类级别筛选,返回 Bean 专属 Advisor
      │           ├─ extendAdvisors(eligibleAdvisors)
      │           └─ sortAdvisors(eligibleAdvisors)
      │
      ├─ 如果有增强器 → createProxy(beanClass, beanName, advisors, targetSource)
      │     ├─ ProxyFactory 复制配置
      │     ├─ 判断代理类型(JDK / CGLIB)
      │     ├─ 添加 Bean 专属 Advisors → AdvisedSupport.advisors
      │     ├─ 设置目标对象 TargetSource
      │     └─ 返回代理对象
      │
      └─ 如果无增强器 → 标记 advisedBeans FALSE 并返回原 Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

说明

  • 明确两类 Advisor

    1. 全局 Advisor:首次扫描所有 @Aspect Bean 时生成并缓存(AAAPC 内部缓存)

    2. 代理对象专属 Advisor:Bean 初始化阶段类级别匹配后加入 AdvisedSupport.advisors[]

  • Advisors 已加入 AdvisedSupport,但拦截器链在方法调用时动态生成。

  • 代理对象替换原始 Bean 返回容器。

# 2. buildAspectJAdvisors 解析 @Aspect

  1. getAdvicesAndAdvisorsForBean 获取 Bean 对应的增强器列表:

    getAdvicesAndAdvisorsForBean(beanClass, beanName)
    └─ findEligibleAdvisors(beanClass, beanName)
          ├─ findCandidateAdvisors() → 获取所有候选 Advisor
          │     ├─ super.findCandidateAdvisors() → 普通 Spring Advisor
          │     └─ aspectJAdvisorsBuilder.buildAspectJAdvisors() → 解析 @Aspect
          ├─ findAdvisorsThatCanApply(candidateAdvisors, beanClass) → 筛选可用 Advisor
          ├─ extendAdvisors(eligibleAdvisors) → 子类可扩展
          └─ sortAdvisors(eligibleAdvisors) → 返回有序 Advisor 列表
    
    1
    2
    3
    4
    5
    6
    7
    8
  2. buildAspectJAdvisors 解析 @Aspect

    buildAspectJAdvisors() → 解析 @Aspect
    ├─ 判断缓存 aspectBeanNames
    │     ├─ 缓存存在 → 直接获取 advisorsCache / aspectFactoryCache
    │     └─ 缓存不存在 → 扫描容器所有 Bean
    │           ├─ 判断是否符合切面资格 → isEligibleBean
    │           ├─ 创建 AspectMetadata & AspectInstanceFactory
    │           ├─ 获取 Advisors → advisorFactory.getAdvisors(factory)
    │           ├─ 缓存 Advisors → advisorsCache / aspectFactoryCache
    │           └─ 缓存切面 Bean 名称 → aspectNames
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

每个切面类的每个切点方法对应一个或多个 Advisors。

# 3. 详解创建代理对象

wrapIfNecessary 中,如果 Bean 匹配到增强器,会调用 createProxy

createProxy(beanClass, beanName, specificInterceptors, targetSource)
├─ 暴露目标类信息 → AutoProxyUtils.exposeTargetClass
├─ 创建 ProxyFactory 并复制配置 → proxyFactory.copyFrom(this)
├─ 判断代理类型(JDK / CGLIB)→ evaluateProxyInterfaces / 添加接口
├─ 添加 Advisors → proxyFactory.addAdvisors(buildAdvisors(...))  # 添加Advisors到当前代理工厂
├─ 设置目标对象 → proxyFactory.setTargetSource
├─ 自定义 ProxyFactory → customizeProxyFactory
├─ 设置冻结与预过滤 → setFrozen / setPreFiltered
├─ 获取 ClassLoader → getProxyClassLoader / SmartClassLoader
└─ 创建并返回代理对象 → proxyFactory.getProxy

1
2
3
4
5
6
7
8
9
10
11

说明:

  • Advisors 被加入 AdvisedSupport 中,但此时还未生成拦截器链, 此处的Advisors是当前代理对象专属

  • 拦截器链在实际方法调用时根据 Advisors 动态生成。

  • Spring 容器刷新完成后,AOP 代理 Bean 已包装返回。

  • 这里的 Advisors 是 Bean 专属的,方法调用时才会生成针对具体方法的拦截器链。

# AOP方法被调用生效流程

在 Spring 容器启动完成后:

  • @Aspect 类已经被扫描,生成对应的 全局 Advisors
  • 目标 Bean 已经根据 类级别匹配,包装为 代理对象 并注册到容器
  • 方法调用时,代理对象根据 方法匹配生成拦截器链,执行增强

以示例切面为例:

package com.web.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void createUser(String name) { System.out.println("保存用户:" + name); }
    public void deleteUser(String name) { System.out.println("删除用户:" + name); }
    public void getUser(String name) { System.out.println("获取用户:" + name); }
}


@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(* com.web.service.UserService.create*(..))")
    public void createPointcut() {}

    @Before("createPointcut()")
    public void beforeCreate() {
        System.out.println("[LogAspect] 创建用户前日志");
    }

    @Pointcut("execution(* com.web.service.UserService.delete*(..))")
    public void deletePointcut() {}

    @Before("deletePointcut()")
    public void beforeDelete() {
        System.out.println("[LogAspect] 删除用户前日志");
    }
}


@Aspect
@Component
public class AuthAspect {

    @Pointcut("execution(* com.web.service.UserService.*User(..))")
    public void allUserMethods() {}

    @Before("allUserMethods()")
    public void checkAuth() {
        System.out.println("[AuthAspect] 权限校验");
    }
}

// 测试
UserService userService = context.getBean(UserService.class);

userService.createUser("Ethan");
userService.deleteUser("Ethan");
userService.getUser("Ethan");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 调用 createUser 方法时的具体流程

假设执行 userService.createUser("Ethan"),流程如下:

  1. 获取 Bean

    • 从容器中获取 UserService,实际上是 AAAPC 创建的 代理对象
  2. 代理对象拦截方法调用

    • proxy.invoke(proxy, createUser, args) 被触发
    • 判断是否是特殊方法(equals、hashCode 等),不是 → 继续
  3. 获取目标对象

    • target = targetSource.getTarget() → 真正的 UserService 实例
  4. 生成方法拦截器链

    • AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

    • 遍历代理对象的 专属 Advisors[]

      • [LogAspect.beforeCreate] 匹配 createUser → 加入拦截器链
      • [AuthAspect.checkAuth] 匹配所有 *User 方法 → 加入拦截器链
    • 生成链:

      [AuthAspect.checkAuth, LogAspect.beforeCreate]
      
      1
  5. 执行拦截器链

    • 创建 ReflectiveMethodInvocation → 调用 proceed()
    • 拦截器链依次执行:
      1. [AuthAspect.checkAuth] → 输出 [AuthAspect] 权限校验
      2. [LogAspect.beforeCreate] → 输出 [LogAspect] 创建用户前日志
    • 最终调用目标方法 createUser("Ethan") → 输出 保存用户:Ethan
  6. 返回结果

    • 拦截器链执行完毕,返回值返回调用方

最终输出顺序

[AuthAspect] 权限校验
[LogAspect] 创建用户前日志
保存用户:Ethan
1
2
3

# 代理方法执行(JDK 动态代理为例)

方法调用 → 代理对象.invoke(proxy, method, args)
           ├─ 处理特殊方法(equals / hashCode / Advised 接口 / DecoratingProxy)
           ├─ 如果 exposeProxy=true → 设置 AopContext 当前代理
           ├─ 获取目标对象 target = targetSource.getTarget()
           ├─ AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
           │     └─ 生成拦截器链(List<MethodInterceptor>)
           ├─ 判断拦截器链是否为空
           │     ├─ 空 → 直接反射调用目标方法
           │     └─ 非空 → new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain)
           │                    └─ 调用 invocation.proceed() 执行拦截器链
           │                          ├─ BeforeAdvice / AroundAdvice / AfterReturning / AfterThrowing
           │                          └─ 最终调用目标方法
           ├─ 处理返回值(this/原型/基本类型 null 等)
           └─ 释放非静态目标对象 & 恢复 AopContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

注意:拦截器链是在方法调用时动态生成的,而不是在 Bean 初始化阶段就固定。

invocation.proceed() 实际上是递归调用, 即用Advisor的拦截器链和当前类进行匹配

# 总结

实际上是 责任链 + 动态代理 实现的效果, 具体流程如下

客户端调用代理对象方法
          ↓
JDK/CGLIB 代理拦截方法调用
          ↓
构造 ReflectiveMethodInvocation
          ↓
责任链 MethodInvocation.proceed()
 ├─ MethodBeforeAdviceInterceptor.invoke() → Before逻辑 → proceed()
 ├─ AroundAdviceInterceptor.invoke() → Around逻辑 → proceed()
 ├─ ... (其他拦截器)
 └─ 目标方法执行
          ↑
沿责任链返回,触发 AfterReturning / AfterThrowing
          ↑
返回最终结果给客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15