前言
在 Spring 框架的核心机制中,AOP 代理的创建逻辑是理解 Spring 事务管理、切面编程、循环依赖解决的关键纽带。很多开发者存在两大核心认知误区:一是认为"Spring 会对所有 Bean 统一进行 AOP 代理",二是混淆"初始化阶段创建代理"与"三级缓存提前创建代理"的逻辑边界。
本文将结合 Spring 核心源码 ,从 Bean 完整生命周期 出发,深度拆解 初始化阶段统一创建 AOP 代理 的底层逻辑,明确区分 正常 Bean 与循环依赖 Bean 的 AOP 创建时机,解答"是否所有 Bean 都会被 AOP"这一核心问题,帮你彻底打通 Spring AOP 与三级缓存的关联逻辑。
一、初始化阶段创建 AOP 代理:核心定位与源码
1. 核心定位
在 非循环依赖 的正常场景下,Spring 并不会通过三级缓存的 ObjectFactory 提前创建代理对象。所有 AOP 代理的创建工作,均会集中在 Bean 生命周期的 initializeBean() 方法中完成 。这是 Spring AOP 的 标准主流程,也是 90% 以上 Bean 的 AOP 代理创建方式。
2. 核心源码:initializeBean 方法
AOP 代理创建的核心入口位于 initializeBean 方法,这是 Bean 初始化的最后一步,源码如下(来自 AbstractAutowireCapableBeanFactory):
java
/**
* 初始化 Bean 的核心方法,包含 Aware 回调、前置处理、初始化方法、后置处理
* @param beanName Bean 名称
* @param bean 原始 Bean 实例
* @param mbd Bean 定义信息
* @return 初始化后的 Bean 实例(可能是代理对象)
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 执行 Aware 接口回调(BeanNameAware、BeanFactoryAware 等)
invokeAwareMethods(beanName, bean);
// 2. 执行 BeanPostProcessor 的前置处理(@PostConstruct 等注解处理也在此阶段)
Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
// 3. 执行初始化方法(afterPropertiesSet 自定义初始化方法、init-method 配置)
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex);
}
// ==========================================
// 🔥 🔥 🔥 【核心关键】AOP 代理创建在这里完成
// ==========================================
// 4. 执行 BeanPostProcessor 的后置处理(AOP 代理创建的核心入口)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
3. 关键核心:applyBeanPostProcessorsAfterInitialization
AOP 代理的创建,本质是通过 Bean 后置处理器(BeanPostProcessor) 实现的。Spring 中负责 AOP 代理创建的核心处理器是 AnnotationAwareAspectJAutoProxyCreator,它实现了 SmartInstantiationAwareBeanPostProcessor 接口,会在 initializeBean 方法的最后一步被触发。
java
/**
* 遍历所有 BeanPostProcessor,执行后置处理
* @param existingBean 已初始化完成的 Bean 实例
* @param beanName Bean 名称
* @return 处理后的 Bean 实例(可能是代理对象)
*/
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
Object result = existingBean;
// 遍历容器中所有的 BeanPostProcessor
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 执行后置处理方法
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
当遍历到 AnnotationAwareAspectJAutoProxyCreator 时,会进入其 postProcessAfterInitialization 方法,最终触发 AOP 代理的创建逻辑。
二、初始化阶段创建 AOP 代理:具体执行步骤
AnnotationAwareAspectJAutoProxyCreator 作为 AOP 代理创建的核心处理器,在初始化阶段的执行流程分为 4 个关键步骤 ,且并非所有 Bean 都会被代理。
步骤 1:匹配切点与拦截器
首先,处理器会判断当前 Bean 是否需要被 AOP 增强,核心逻辑是 匹配切点(Pointcut):
java
/**
* 判断 Bean 是否需要被代理,核心方法
* @param beanClass Bean 的类对象
* @param beanName Bean 名称
* @return 匹配的拦截器数组,无则返回 DO_NOT_PROXY
*/
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 1. 寻找所有匹配当前 Bean 的切面通知器(Advisor)
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
// 无匹配的切面,无需代理,返回 DO_NOT_PROXY
return DO_NOT_PROXY;
}
// 有匹配的切面,封装拦截器返回
return advisors.toArray();
}
核心判断逻辑:
- 遍历所有自定义的
@Aspect切面,匹配当前 Bean 的类和方法是否符合切点规则; - 检查是否存在
@Transactional等事务注解,Spring 会自动为其创建代理; - 排除系统内部类、基础设施类(如
String、Integer等)。
步骤 2:创建代理对象
如果当前 Bean 匹配切点规则,处理器会创建 CGLIB 代理 或 JDK 动态代理:
java
/**
* 创建 AOP 代理对象
* @param beanClass 目标类
* @param beanName Bean 名称
* @param specificInterceptors 匹配的拦截器
* @param targetSource 目标源
* @return 代理对象
*/
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 1. 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 2. 判断使用 JDK 动态代理还是 CGLIB 代理
// 目标类实现接口 → 优先使用 JDK 动态代理
// 目标类未实现接口 → 强制使用 CGLIB 代理
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 3. 封装拦截器
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 4. 自定义代理工厂(可扩展)
customizeProxyFactory(proxyFactory);
// 5. 创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
步骤 3:记录代理信息,避免重复创建
为了避免后续重复创建代理,处理器会将代理信息存入缓存:
java
// 存入 earlyProxyReferences 缓存,标记已创建早期代理
this.earlyProxyReferences.put(cacheKey, bean);
// 存入 advisedBeans 缓存,标记是否需要代理
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 存入 proxyTypes 缓存,记录代理类类型
this.proxyTypes.put(cacheKey, proxy.getClass());
步骤 4:返回代理对象
最终,initializeBean 方法会将 代理对象 作为返回值,Spring 容器中管理的不再是原始 Bean 实例,而是代理实例。
三、核心问题:是不是所有 Bean 都会进行 AOP?
绝对不是! 这是 Spring AOP 最核心的认知误区。
Spring AOP 采用 "按需代理" 原则,只有满足以下条件之一的 Bean 才会被创建代理:
- 类或方法上存在 AOP 切面注解 :如
@Around、@Before、@After等切面方法匹配的类/方法; - 存在事务注解 :
@Transactional标注的类或方法,Spring 会为其创建事务代理; - 实现了 AOP 相关接口 :如
IntroductionInterceptor等,需要动态代理增强; - 自定义 AOP 规则匹配:通过 XML 配置的 AOP 切点,匹配的 Bean 才会被代理。
不会被 AOP 代理的 Bean 类型
以下 90% 以上的普通 Bean,直接返回原始对象,不会创建代理:
- 纯
@Service、@Repository、@Component注解的类,且无事务、无切面匹配; - 基础数据类型、包装类、字符串等系统类;
- 仅实现普通业务逻辑,无任何增强需求的类;
- 配置类(
@Configuration)仅在处理@Bean方法时可能代理,普通配置类本身不代理。
源码佐证
getAdvicesAndAdvisorsForBean 方法的核心逻辑是寻找匹配的拦截器 ,如果没有匹配的拦截器,直接返回 DO_NOT_PROXY,后续不会创建代理:
java
if (advisors.isEmpty()) {
// 无匹配的切面/拦截器,无需代理
return DO_NOT_PROXY;
}
四、两种 AOP 创建场景对比:初始化阶段 vs 三级缓存
Spring 中存在 两种 AOP 代理创建场景 ,分别对应 正常 Bean 和 循环依赖 Bean,两者的创建时机、逻辑和目的完全不同,核心差异如下表所示:
| 对比维度 | 正常 Bean(无循环依赖) | 循环依赖 Bean(A 依赖 B、B 依赖 A) |
|---|---|---|
| 创建时机 | initializeBean 初始化最后一步 |
三级缓存 ObjectFactory 执行时(依赖注入阶段) |
| 触发条件 | 正常 Bean 初始化完成,后置处理器触发 | 循环依赖发生,其他 Bean 提前获取早期引用 |
| 代理创建逻辑 | 标准 AOP 代理创建流程(wrapIfNecessary) |
早期代理创建流程(getEarlyBeanReference) |
| 是否所有 Bean 代理 | 仅匹配切点的 Bean 代理,按需创建 | 仅匹配切点的 Bean 代理,按需创建 |
| 代理对象唯一性 | 唯一,容器中仅存代理对象 | 唯一,最终与初始化阶段代理对象一致 |
| 三级缓存作用 | 仅存入工厂逻辑,未执行,最终删除 | 执行工厂逻辑,创建早期代理,移入二级缓存 |
1. 正常 Bean 的 AOP 流程(无循环依赖)
- 实例化原始 Bean 对象;
- 加入三级缓存(存入
ObjectFactory工厂逻辑,未执行); - 填充属性(从一级缓存获取其他成品 Bean);
- 执行初始化
initializeBean; - 初始化最后一步,触发
AnnotationAwareAspectJAutoProxyCreator,按需创建 AOP 代理; - 将代理对象/原始对象放入一级缓存;
- 删除三级缓存(工厂逻辑从未执行);
- 全程未使用二级缓存。
2. 循环依赖 Bean 的 AOP 流程(A 依赖 B、B 依赖 A)
- 线程 1 实例化原始 A 对象,加入三级缓存(存入 A 的工厂逻辑);
- 线程 1 填充 A 属性,依赖 B,调用
getBean(B); - 线程 1 实例化原始 B 对象,加入三级缓存(存入 B 的工厂逻辑);
- 线程 1 填充 B 属性,依赖 A,调用
getBean(A); - 线程 1 从三级缓存获取 A 的工厂逻辑,执行
getEarlyBeanReference,按需创建早期 AOP 代理; - 将早期代理对象放入二级缓存,删除三级缓存;
- B 获取到 A 的早期代理,完成属性填充和初始化,放入一级缓存;
- 线程 1 回到 A 的创建流程,完成 A 的属性填充;
- 初始化阶段,发现 A 已存在早期代理,跳过 AOP 代理创建;
- 将 A 的早期代理对象放入一级缓存,删除二级缓存;
- 最终,A、B 均为成品代理对象,代理对象唯一,无替换风险。
五、核心设计原理:为什么要分两个阶段创建 AOP?
1. 正常 Bean:初始化阶段创建 AOP 的必要性
AOP 代理的创建依赖于 完整的 Bean 实例 (属性已填充、初始化方法已执行)。如果在实例化后、属性填充前创建代理,会导致 代理对象包裹的原始 Bean 属性为 null,后续调用目标方法时会出现空指针异常。
因此,Spring 规定:AOP 代理必须在 Bean 属性完全填充、初始化方法执行完成后创建,这是保证代理对象可用性的核心前提。
2. 循环依赖 Bean:三级缓存提前创建 AOP 的必要性
循环依赖的核心矛盾是 "创建 A 需要 B,创建 B 需要 A" ,如果等待初始化阶段再创建 AOP 代理,会导致 死循环等待,无法完成 Bean 创建。
因此,Spring 通过三级缓存的 ObjectFactory 提前创建 早期代理对象 ,让循环依赖的 Bean 可以相互引用,同时通过 earlyProxyReferences 缓存保证 代理对象唯一性,避免初始化阶段重复创建代理。
3. 核心设计原则:延迟创建 + 唯一代理
Spring AOP 采用 "延迟创建代理" 原则,避免不必要的性能开销;同时通过 缓存机制 保证 代理对象唯一性,无论正常场景还是循环依赖场景,容器中最终只存在一个代理实例,避免对象替换导致的类型不一致、引用异常等问题。
六、源码总结:核心逻辑闭环
- 正常 Bean :AOP 代理在
initializeBean方法的applyBeanPostProcessorsAfterInitialization阶段创建,由AnnotationAwareAspectJAutoProxyCreator触发,按需匹配切点,仅对符合条件的 Bean 代理; - 循环依赖 Bean :AOP 代理在三级缓存的
ObjectFactory执行时创建,通过getEarlyBeanReference生成早期代理,仅为解决循环依赖,最终与初始化阶段代理对象一致; - 通用原则 :并非所有 Bean 都会被 AOP 代理,Spring 采用"按需代理"原则,通过切点匹配控制代理范围;
- 核心保障:全局锁、缓存机制、早期代理记录,保证并发场景下代理对象的唯一性和线程安全。
七、最终结论
- "在初始化阶段统一创建 AOP 代理"是 Spring AOP 的标准主流程,适用于 90% 以上的正常 Bean;
- 并非所有 Bean 都会进行 AOP 代理,仅对匹配切点(如事务、切面)的 Bean 按需创建;
- 循环依赖 Bean 的 AOP 代理是提前创建的早期代理,最终会与初始化阶段的代理对象保持一致,避免对象替换风险;
- 三级缓存的 AOP 工厂逻辑仅为解决循环依赖而设计,正常 Bean 场景下不会执行,仅为走过场。
这一设计既保证了 AOP 代理的正确性(基于完整 Bean 实例),又解决了循环依赖的核心矛盾,同时通过"按需代理"降低了框架性能开销,是 Spring 框架设计中"严谨性"与"灵活性"的完美体现。