# 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 获取代理
}
2
3
4
5
6
7
8
作用:通过
@Import将AspectJAutoProxyRegistrar导入容器,注册 AOP 基础设施 Bean。核心 Bean:
AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor),负责扫描@Aspect并为符合条件的 Bean 创建代理。
# 核心注册流程
@EnableAspectJAutoProxy
└─ @Import(AspectJAutoProxyRegistrar)
AspectJAutoProxyRegistrar.registerBeanDefinitions
├─ 注册 AOP 自动代理创建器
│ └─ AnnotationAwareAspectJAutoProxyCreator (核心 BeanPostProcessor)
│
└─ 解析注解参数
├─ proxyTargetClass = true → 强制使用 CGLIB
└─ exposeProxy = true → 允许通过 AopContext 获取当前代理
2
3
4
5
6
7
8
9
10
AnnotationAwareAspectJAutoProxyCreator是 Spring AOP 的核心组件,负责扫描@Aspect注解并为符合条件的 Bean 创建代理对象。它是 AOP 代理生成的入口,但并非在普通refresh()扫描阶段注册,而是通过ImportBeanDefinitionRegistrar提前注册为基础设施 Bean。
# 关键类解析
AnnotationAwareAspectJAutoProxyCreator
→ AspectJAwareAdvisorAutoProxyCreator
→ AbstractAdvisorAutoProxyCreator
→ AbstractAutoProxyCreator
→ SmartInstantiationAwareBeanPostProcessor
→ BeanPostProcessor
2
3
4
5
6
- 继承关系说明
- 本质是 BeanPostProcessor 的一种
- 作为基础设施 Bean 提前注册,不经过普通 Bean 扫描
- 核心方法
AbstractAutoProxyCreator#postProcessBeforeInstantiation- 在 Bean 初始化后调用,用于判断是否需要生成代理对象, 实现 AOP 功能
- 主要职责
- 扫描和解析
@Aspect注解 - 构建对应的
Advisor - 在 Bean 初始化完成后生成 JDK 或 CGLIB 代理对象
- 扫描和解析
- 特点
- 提前注册的基础设施 Bean
- 不经过普通 Bean 扫描逻辑
- 为容器中的目标 Bean 提供 AOP 增强
# 触发 AOP 代理生成
Spring AOP 的代理生成逻辑可以拆成两个阶段:
AAAPC (
AnnotationAwareAspectJAutoProxyCreator) 注册与初始化普通 Bean 初始化调用后置处理方法,判断是否需要创建代理
这样划分可以清楚地理解 @Aspect 扫描时机 与 代理对象创建流程。
# 1. AAAPC 注册与初始化
当开启注解驱动 AOP 时,@EnableAspectJAutoProxy 会通过 AspectJAutoProxyRegistrar 注册 AAAPC:
@EnableAspectJAutoProxy
└─ @Import(AspectJAutoProxyRegistrar)
└─ registerBeanDefinitions()
└─ AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
2
3
4
- AAAPC 是 BeanPostProcessor 类型的基础设施 Bean
- 它会被提前注册到容器,不经过普通 Bean 扫描
- Spring 容器刷新时实例化 AAAPC:
finishBeanFactoryInitialization(beanFactory)
└─ preInstantiateSingletons()
└─ getBean("annotationAwareAspectJAutoProxyCreator")
└─ createBean → doCreateBean → 实例化 AAAPC
2
3
4
重点:
- AAAPC 初始化自身时,并不立即扫描 @Aspect Bean。
- 它在实例化完成后就具备了为后续目标 Bean 创建代理的能力。
# 2. 普通 Bean 初始化触发代理创建
普通 Bean 初始化时,会调用 AAAPC 的 postProcessAfterInitialization 方法:
applyBeanPostProcessorsAfterInitialization(existingBean, beanName)
└─ 遍历所有 BeanPostProcessor
└─ 调用 postProcessAfterInitialization(result, beanName)
└─ AnnotationAwareAspectJAutoProxyCreator.wrapIfNecessary(bean, beanName)
2
3
4
关键逻辑:
普通 Bean 首次初始化时, 扫描 @Aspect → 全局 Advisor 缓存
- 当 AAAPC 初始化或首次处理 Bean 时,会扫描容器中所有
@AspectBean。 - 每个切面类的每个切点方法会生成一个或多个 Advisor。
- 这些 Advisor 会被添加到 AAAPC 内部缓存,这个缓存是 全局可复用:
advisorsCache(缓存 Advisor 列表)aspectFactoryCache(缓存切面实例工厂)
- 此时并不会判断某个 Bean 是否匹配,只是先把所有切面方法都生成对应 Advisor。
⚠️ 这个阶段的作用:把所有切面方法转成 Advisor,并缓存起来。
- 当 AAAPC 初始化或首次处理 Bean 时,会扫描容器中所有
Bean 初始化 → 为当前 Bean 生成代理对象
当普通 Bean 初始化完成后,AAAPC 的
postProcessAfterInitialization会被调用。获取全局 Advisor 缓存
- AAAPC 拿到所有已生成的 Advisor(上一步缓存的列表)。
类级别匹配
调用
findAdvisorsThatCanApply(candidateAdvisors, beanClass)只有匹配当前 Bean 的 Advisor 才会被选中。
生成代理对象
创建
ProxyFactory或 CGLIB 代理将匹配的 Advisor 添加到该 Bean 的
AdvisedSupport.advisors[]返回代理对象替换原 Bean
⚠️ 这个阶段的作用:每个 Bean 的代理对象只保存自己匹配的 Advisor,方法调用时再根据切点生成拦截器链。
# 3. 源码解析
# 1. AbstractAutoProxyCreator 详解
AnnotationAwareAspectJAutoProxyCreator 继承自 AbstractAutoProxyCreator,主要通过 wrapIfNecessary 和 createProxy 完成代理包装:
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
说明:
明确两类 Advisor
全局 Advisor:首次扫描所有
@AspectBean 时生成并缓存(AAAPC 内部缓存)代理对象专属 Advisor:Bean 初始化阶段类级别匹配后加入
AdvisedSupport.advisors[]
Advisors已加入AdvisedSupport,但拦截器链在方法调用时动态生成。代理对象替换原始 Bean 返回容器。
# 2. buildAspectJAdvisors 解析 @Aspect
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
8buildAspectJAdvisors解析 @AspectbuildAspectJAdvisors() → 解析 @Aspect ├─ 判断缓存 aspectBeanNames │ ├─ 缓存存在 → 直接获取 advisorsCache / aspectFactoryCache │ └─ 缓存不存在 → 扫描容器所有 Bean │ ├─ 判断是否符合切面资格 → isEligibleBean │ ├─ 创建 AspectMetadata & AspectInstanceFactory │ ├─ 获取 Advisors → advisorFactory.getAdvisors(factory) │ ├─ 缓存 Advisors → advisorsCache / aspectFactoryCache │ └─ 缓存切面 Bean 名称 → aspectNames1
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
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");
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"),流程如下:
获取 Bean
- 从容器中获取
UserService,实际上是 AAAPC 创建的 代理对象
- 从容器中获取
代理对象拦截方法调用
proxy.invoke(proxy, createUser, args)被触发- 判断是否是特殊方法(equals、hashCode 等),不是 → 继续
获取目标对象
target = targetSource.getTarget()→ 真正的UserService实例
生成方法拦截器链
AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)遍历代理对象的 专属 Advisors[]:
[LogAspect.beforeCreate]匹配createUser→ 加入拦截器链[AuthAspect.checkAuth]匹配所有*User方法 → 加入拦截器链
生成链:
[AuthAspect.checkAuth, LogAspect.beforeCreate]1
执行拦截器链
- 创建
ReflectiveMethodInvocation→ 调用proceed() - 拦截器链依次执行:
[AuthAspect.checkAuth]→ 输出[AuthAspect] 权限校验[LogAspect.beforeCreate]→ 输出[LogAspect] 创建用户前日志
- 最终调用目标方法
createUser("Ethan")→ 输出保存用户:Ethan
- 创建
返回结果
- 拦截器链执行完毕,返回值返回调用方
最终输出顺序:
[AuthAspect] 权限校验
[LogAspect] 创建用户前日志
保存用户:Ethan
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
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
↑
返回最终结果给客户端
2
3
4
5
6
7
8
9
10
11
12
13
14
15