Spring的 三级缓存 与 AOP 笔记251009
Spring 的三级缓存机制与 AOP 代理有着密切的关系,正是为了正确处理 AOP 代理对象的循环依赖问题,才需要三级缓存而不仅仅是两级缓存。
核心问题:AOP 代理与循环依赖的冲突
问题场景
@Component
public class A {
@Autowired
private B b;
@Async // 这个注解会让 Spring 为 A 创建代理
public void methodA() {}
}
@Component
public class B {
@Autowired
private A a; // 这里期望注入的是 A 的代理对象
}
如果没有三级缓存,会出现什么问题?
三级缓存如何解决 AOP 代理问题
关键机制:ObjectFactory 和 getEarlyBeanReference
// 三级缓存中的 ObjectFactory 定义
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference 方法详解
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// 关键:这里会调用 AOP 相关的后置处理器
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
AOP 代理在循环依赖中的创建时机
正常情况(无循环依赖)
// Bean 的完整创建流程
1. 实例化
2. 填充属性
3. 初始化
4. AOP 代理创建 ← 代理在初始化完成后创建
循环依赖情况
// 有循环依赖时,AOP 代理需要提前创建
1. 实例化 A
2. 暴露 ObjectFactory(三级缓存) ← 此时准备好创建代理的能力
3. 填充属性时发现依赖 B
4. 创建 B,B 需要 A
5. 从三级缓存获取 A ← 触发代理的提前创建
6. 将 A 的代理对象注入 B
7. 完成 B 的创建
8. 完成 A 的创建
具体流程分析
步骤 1:A 实例化并暴露工厂
// A 被实例化(原始对象)
A rawA = new A();
// 将能够生产 A 代理的工厂放入三级缓存
addSingletonFactory("A", () -> {
// 这个 lambda 只有在发生循环依赖时才会被调用
for (BeanPostProcessor bp : postProcessors) {
if (bp instanceof AbstractAutoProxyCreator) {
// AOP 后置处理器创建代理
return ((AbstractAutoProxyCreator) bp).getEarlyBeanReference(rawA, "A");
}
}
return rawA;
});
步骤 2:B 依赖 A 时触发代理创建
// B 在填充属性时需要 A
Object earlyA = null;
// 从三级缓存获取
ObjectFactory<?> factory = singletonFactories.get("A");
if (factory != null) {
// 调用工厂方法,触发 getEarlyBeanReference
earlyA = factory.getObject(); // 这里返回的是 A 的代理对象
// 将代理对象放入二级缓存
earlySingletonObjects.put("A", earlyA);
singletonFactories.remove("A");
}
// 将 A 的代理对象注入 B
b.setA((A) earlyA);
为什么需要三级缓存?
如果只有两级缓存会怎样?
方案一:二级缓存 + 提前创建所有代理
// 实例化后立即创建代理
Object bean = createBeanInstance(beanName, mbd, args);
// 立即创建 AOP 代理
Object proxy = createProxy(bean);
// 将代理放入二级缓存
earlySingletonObjects.put(beanName, proxy);
问题:
- 浪费资源:即使没有循环依赖,也提前创建了代理
- 可能创建不必要的代理:有些 Bean 根本不会被循环依赖
方案二:二级缓存 + 延迟创建代理
// 但这样在循环依赖时,注入的就是原始对象而不是代理对象
// B 中注入的是 A 的原始对象,而不是 A 的代理对象
// 导致 @Async、@Transactional 等注解失效
三级缓存的优势
// 三级缓存的按需代理机制
if (发生循环依赖) {
// 从三级缓存获取,触发代理创建
Object proxy = singletonFactories.get(beanName).getObject();
return proxy;
} else {
// 正常流程,在初始化后创建代理
return doCreateBean(beanName, mbd, args);
}
AbstractAutoProxyCreator 的实现
Spring AOP 的核心类如何配合三级缓存工作:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
// 保存早期代理引用
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 记录这个 Bean 需要早期代理
earlyProxyReferences.put(cacheKey(beanName), bean);
// 创建代理
return wrapIfNecessary(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经创建过早期代理,这里就不再重复创建
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName);
}
}
return bean;
}
}
实际案例演示
场景:@Transactional 的循环依赖
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
public void createUser() {
// 事务方法
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 这里需要注入的是 UserService 的代理
}
执行流程:
UserService实例化,暴露ObjectFactory到三级缓存- 填充
orderService属性,开始创建OrderService OrderService实例化,填充userService属性- 从三级缓存获取
UserService,触发getEarlyBeanReference AbstractAutoProxyCreator为UserService创建事务代理- 代理对象注入到
OrderService中 - 完成两个 Bean 的创建
总结
三级缓存与 AOP 的关系可以概括为:
- 按需代理:只有在发生循环依赖时才提前创建代理,避免资源浪费
- 代理一致性:确保循环依赖中注入的都是代理对象,而不是原始对象
- 避免重复创建:通过
earlyProxyReferences机制防止代理被重复创建 - 设计优雅:
ObjectFactory的延迟执行特性完美解决了 AOP 代理的时机问题
这种设计确保了 Spring AOP 在各种复杂场景下(包括循环依赖)都能正常工作,是 Spring 框架中非常精妙的解决方案。
1️⃣ 参考 1
Spring 三级缓存与 AOP 的协同工作机制
1. 问题背景
当循环依赖遇到 AOP 代理时,情况变得更加复杂:
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 需要AOP代理
public void createUser() {
// 业务逻辑
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 这里需要注入代理对象,而不是原始对象
public void createOrder() {
userService.createUser(); // 需要调用代理方法以确保事务生效
}
}
2. AOP 代理的创建时机问题
2.1 常规 AOP 代理创建流程
// 正常的Bean创建流程(无循环依赖)
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
// ... 初始化前处理
// 调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
// 初始化后处理 - AOP代理在这里创建
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
问题:在循环依赖场景中,Bean B 在 Bean A 初始化完成前就需要引用 A,但此时 AOP 代理还未创建。
3. 三级缓存与 AOP 的协同解决方案
3.1 关键机制:提前创建代理对象
// 在 DefaultSingletonBeanRegistry 中
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AbstractAutoProxyCreator 在这里创建早期代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
3.2 AbstractAutoProxyCreator 的实现
public abstract class AbstractAutoProxyCreator {
// 缓存早期代理引用
private final Map<Object, Object> earlyProxyReferences =
new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 记录这个Bean需要早期代理
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 包装Bean(如果需要代理)
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经创建过早期代理,则不再重复创建
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 正常创建代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否需要创建代理(基于@Transactional、@Async等注解)
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是基础设施类或应该跳过的类,不创建代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
4. 完整流程分析
4.1 循环依赖 + AOP 场景的完整流程
// 场景:UserService (@Transactional) ←→ OrderService
// 步骤1:开始创建 UserService
1. getBean("userService")
2. createBeanInstance() - 实例化原始UserService对象
3. addSingletonFactory("userService",
() -> getEarlyBeanReference("userService", mbd, userServiceRaw))
// 步骤2:在getEarlyBeanReference中创建早期代理
4. AbstractAutoProxyCreator.getEarlyBeanReference() 被调用
5. 检查UserService是否需要代理(发现@Transactional注解)
6. 创建UserService的代理对象:userServiceProxy
7. 将(userServiceRaw → userServiceProxy) 映射存入earlyProxyReferences
8. 返回userServiceProxy到三级缓存
// 步骤3:属性注入,发现依赖OrderService
9. populateBean("userService") - 需要orderService
10. getBean("orderService")
// 步骤4:创建OrderService
11. createBeanInstance() - 实例化OrderService
12. addSingletonFactory("orderService", ...)
13. populateBean("orderService") - 需要userService
14. getBean("userService")
// 步骤5:获取UserService的早期引用
15. 从三级缓存获取UserService的ObjectFactory
16. 调用getObject(),返回userServiceProxy
17. 将userServiceProxy放入二级缓存
18. OrderService持有userServiceProxy,完成属性注入
19. OrderService完成初始化,放入一级缓存
// 步骤6:回到UserService的创建
20. UserService获得OrderService实例,完成属性注入
21. 调用initializeBean("userService")
22. 执行postProcessAfterInitialization
23. AbstractAutoProxyCreator.postProcessAfterInitialization()
- 检查earlyProxyReferences,发现userServiceRaw已有早期代理
- 移除earlyProxyReferences中的记录
- 直接返回原始Bean(因为代理已经在步骤2创建)
// 步骤7:完成创建
24. 将userServiceProxy放入一级缓存(替换原始Bean)
4.2 时序图表示
时间轴: t1 t2 t3 t4 t5
UserService: 实例化 → 创建早期代理 → 属性注入需要B → → 完成初始化
OrderService: 实例化 → 属性注入需要A → 完成初始化
三级缓存User: 空 有代理工厂 有代理工厂 空 空
二级缓存User: 空 空 空 有代理实例 空
一级缓存User: 空 空 空 空 有代理实例
earlyProxyReferences: 空 有映射记录 有映射记录 有映射记录 空
5. 特殊情况处理
5.1 多个 AOP 切面的情况
@Service
public class ComplexService {
@Autowired
private AnotherService anotherService;
@Transactional
@Async
@Retryable
public void complexMethod() {
// 多个AOP切面
}
}
@Service
public class AnotherService {
@Autowired
private ComplexService complexService; // 需要包含所有切面的代理
}
处理机制:
getEarlyBeanReference会创建包含所有适用切面的完整代理- 后续的
postProcessAfterInitialization不会重复创建
5.2 自定义 BeanPostProcessor 的情况
@Component
public class CustomBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
// 自定义的早期引用处理
if (bean instanceof CustomAnnotated) {
return createCustomProxy(bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 确保与早期引用的一致性
return bean;
}
}
6. 源码调试技巧
6.1 调试断点设置
// 关键调试断点位置
1. AbstractAutoProxyCreator.getEarlyBeanReference()
2. AbstractAutoProxyCreator.postProcessAfterInitialization()
3. DefaultSingletonBeanRegistry.getSingleton()
4. DefaultSingletonBeanRegistry.addSingletonFactory()
5. AbstractAutowireCapableBeanFactory.doCreateBean()
6.2 调试日志配置
########## application.properties
logging.level.org.springframework.beans.factory.support=DEBUG
logging.level.org.springframework.aop.framework.autoproxy=DEBUG
logging.level.org.springframework.transaction=DEBUG
########## 查看代理创建过程
logging.level.org.springframework.aop=TRACE
7. 常见问题与解决方案
7.1 代理对象方法调用问题
@Service
public class ProblemService {
@Autowired
private AnotherService anotherService;
@Transactional
public void publicMethod() {
privateMethod(); // 这里事务不会生效!
}
@Transactional
private void privateMethod() {
// 私有方法上的@Transactional无效
}
public void callInternal() {
// 正确做法:通过代理对象调用
((ProblemService) AopContext.currentProxy()).publicMethod();
}
}
解决方案:
@EnableAspectJAutoProxy(exposeProxy = true) // 启用AopContext
public class AppConfig {
}
@Service
public class CorrectService {
@Transactional
public void methodA() {
// 通过代理调用确保事务传播
((CorrectService) AopContext.currentProxy()).methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 新事务
}
}
7.2 初始化顺序问题
@Component
public class EarlyInitBean {
@Autowired
private TransactionalService transactionalService;
@PostConstruct
public void init() {
// 在初始化方法中调用代理方法
transactionalService.doSomething(); // 可能代理还未完全准备好
}
}
解决方案:
@Component
public class SafeInitBean {
@Autowired
private ApplicationContext applicationContext;
private TransactionalService transactionalService;
@PostConstruct
public void init() {
// 延迟获取代理Bean
this.transactionalService = applicationContext.getBean(TransactionalService.class);
transactionalService.doSomething(); // 安全的代理调用
}
}
8. 总结
Spring 三级缓存与 AOP 的协同工作机制体现了框架设计的精巧性:
8.1 核心要点
- 提前暴露:在 Bean 初始化前通过三级缓存暴露引用
- 早期代理:
getEarlyBeanReference在循环依赖时提前创建代理对象 - 避免重复:
postProcessAfterInitialization检查并避免重复创建代理 - 一致性保证:确保循环依赖中注入的是代理对象而非原始对象
8.2 设计优势
- 解决循环依赖:打破 Bean 创建的循环等待
- 保证 AOP 功能:确保代理对象的方法拦截正常work
- 性能优化:避免重复创建代理对象
- 扩展性:支持自定义
BeanPostProcessor参与代理创建
8.3 实践建议
- 理解代理机制,避免在类内部调用代理方法
- 在复杂 AOP 场景中合理使用
@Lazy注解 - 在调试时关注
earlyProxyReferences的状态变化 - 对于性能敏感的应用,尽量减少循环依赖
2️⃣ 参考 2
Spring 三级缓存与 AOP 的协同工作机制
1. 问题背景:AOP 与循环依赖的冲突
1.1 AOP 代理的创建时机
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 需要 AOP 代理
public void createUser() {
// 业务逻辑
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 这里应该注入代理对象
}
问题:如果 UserService 需要 AOP 代理,在循环依赖场景下,OrderService 应该注入代理对象而不是原始对象。
2. 三级缓存如何支持 AOP
2.1 ObjectFactory 的关键作用
// 在 Bean 实例化后立即创建 ObjectFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
// 将 ObjectFactory 放入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
}
}
}
// ObjectFactory 的具体实现
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
2.2 getEarlyBeanReference 方法
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// 关键:这里可能会返回代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
3. AbstractAutoProxyCreator 的实现
3.1 AOP 代理创建器的核心逻辑
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
// 早期 Bean 引用的缓存
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 缓存 key
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 记录当前 Bean 需要早期代理
this.earlyProxyReferences.put(cacheKey, bean);
// 创建代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经在早期创建过代理,这里不再重复创建
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否需要创建代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是基础设施类或应该跳过的类,不创建代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
4. 完整流程分析(AOP + 循环依赖)
4.1 UserService 和 OrderService 的创建过程
// 场景:UserService 有 @Transactional,需要 AOP 代理
// 步骤1:创建 UserService
1. instance = instantiate UserService // 实例化原始对象
2. addSingletonFactory("userService",
() -> getEarlyBeanReference("userService", mbd, userService))
// 此时 ObjectFactory 会调用 AbstractAutoProxyCreator.getEarlyBeanReference()
// 如果 UserService 需要代理,这里返回代理对象
// 步骤2:填充 UserService 属性
3. populateBean("userService") → 需要 orderService
4. getBean("orderService") → createBean("orderService")
// 步骤3:创建 OrderService
5. instance = instantiate OrderService
6. addSingletonFactory("orderService", ...)
// 步骤4:填充 OrderService 属性
7. populateBean("orderService") → 需要 userService
8. getBean("userService") → getSingleton("userService")
// 关键步骤:获取 UserService 早期引用
9. getSingleton("userService") 流程:
- 三级缓存找到 ObjectFactory
- 调用 objectFactory.getObject()
- 触发 getEarlyBeanReference("userService", mbd, userService)
- AbstractAutoProxyCreator 创建 UserService 的代理对象
- 代理对象放入二级缓存
// 步骤5:继续 OrderService 创建
10. 将 UserService 的代理对象注入 OrderService
11. OrderService 完成初始化,放入一级缓存
// 步骤6:继续 UserService 创建
12. 将完整的 OrderService 注入 UserService
13. 调用 postProcessAfterInitialization("userService")
- AbstractAutoProxyCreator 检查 earlyProxyReferences
- 发现 userService 已经创建过早期代理,直接返回原始对象
- 确保最终 Bean 是代理对象
// 最终:OrderService 持有 UserService 的代理对象
4.2 为什么需要三级缓存而不是二级缓存?
// 假设只有二级缓存,没有 ObjectFactory:
addSingletonFactory(beanName, () -> bean); // 直接放入原始对象
// 问题1:无法处理 AOP 代理
// OrderService 注入的是 UserService 原始对象,不是代理对象
// 问题2:代理对象创建时机不确定
// 可能在循环依赖解决后才创建代理,导致依赖注入不一致
// 问题3:可能创建多个代理对象实例
5. 特殊场景分析
5.1 多层代理的情况
@Service
public class ComplexService {
@Autowired
private AnotherService anotherService;
@Transactional
@Async
public void complexMethod() {
// 既有事务又有异步
}
}
处理流程:
getEarlyBeanReference创建第一层代理(如事务代理)- 如果有多个
SmartInstantiationAwareBeanPostProcessor,会依次包装 - 最终返回多层代理对象
5.2 自定义 BeanPostProcessor
@Component
public class CustomBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 自定义早期引用逻辑
if (bean instanceof MySpecialInterface) {
return createCustomProxy(bean);
}
return bean;
}
}
6. 源码调试技巧
6.1 关键断点位置
// 1. 三级缓存操作
DefaultSingletonBeanRegistry.getSingleton()
DefaultSingletonBeanRegistry.addSingletonFactory()
// 2. AOP 代理创建
AbstractAutoProxyCreator.getEarlyBeanReference()
AbstractAutoProxyCreator.postProcessAfterInitialization()
AbstractAutoProxyCreator.wrapIfNecessary()
// 3. Bean 创建流程
AbstractAutowireCapableBeanFactory.doCreateBean()
AbstractAutowireCapableBeanFactory.createBeanInstance()
AbstractAutowireCapableBeanFactory.populateBean()
6.2 调试观察点
// 观察缓存状态变化:
- singletonObjects (一级缓存)
- earlySingletonObjects (二级缓存)
- singletonFactories (三级缓存)
- AbstractAutoProxyCreator.earlyProxyReferences
// Bean 身份验证:
- 原始对象:userService@1234
- 代理对象:userService$$EnhancerBySpringCGLIB@5678
7. 常见问题与解决方案
7.1 @Async 方法的循环依赖
@Service
public class AsyncService {
@Autowired
private AnotherService anotherService;
@Async
public void asyncMethod() {
// 异步方法
}
}
// 解决方案1:使用 @Lazy
@Service
public class AnotherService {
@Lazy
@Autowired
private AsyncService asyncService;
}
// 解决方案2:避免在异步方法中调用自身
7.2 自我注入的代理问题
@Service
public class SelfInjectionService {
@Autowired
private SelfInjectionService self;
public void methodA() {
this.self.methodB(); // 希望通过代理调用
}
@Transactional
public void methodB() {
// 事务方法
}
}
// 必须通过代理调用才能触发事务
// 在 methodA 中直接调用 methodB() 不会走代理
8. 性能优化考虑
8.1 早期代理创建的代价
// 优化策略:延迟代理创建
@Component
public class LazyInitBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
private final Set<String> needEarlyProxy = ConcurrentHashMap.newKeySet();
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 只有真正需要时才创建早期代理
if (needEarlyProxy.contains(beanName)) {
return wrapIfNecessary(bean, beanName);
}
return bean;
}
}
9. 总结
Spring 三级缓存与 AOP 的协同工作机制:
9.1 核心价值
- 解决代理对象的循环依赖:确保在循环依赖中注入的是代理对象
- 保证代理单例性:在整个生命周期中,同一个 Bean 名称返回同一个代理对象
- 灵活的代理创建:支持多种代理方式和自定义扩展
9.2 关键设计点
- ObjectFactory 延迟创建:只有在真正需要时才创建代理对象
- earlyProxyReferences 跟踪:避免重复创建代理
- SmartInstantiationAwareBeanPostProcessor 扩展点:支持自定义代理逻辑
9.3 实践建议
- 理解代理时机:知道什么时候创建早期代理,什么时候创建常规代理
- 避免复杂的循环依赖:即使技术能解决,也要从设计上避免
- 合理使用 @Lazy:在复杂场景下使用延迟注入简化依赖关系
通过三级缓存机制,Spring 优雅地解决了 AOP 代理与循环依赖的协同工作问题,这是 Spring 框架设计精妙之处的重要体现。
3️⃣ 参考 3
Spring 三级缓存与 AOP 的协同机制
概述
Spring 的三级缓存机制与 AOP 代理有着紧密的协作关系。当存在循环依赖且 Bean 需要被 AOP 代理时,三级缓存机制确保了正确的代理对象创建和注入。
AOP 代理的特殊性
代理对象的创建时机
@Component
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
public void createUser() {
// 事务方法
}
}
@Component
public class OrderService {
@Autowired
private UserService userService;
public void createOrder() {
// 业务方法
}
}
在这种情况下,UserService 需要被事务代理,同时存在循环依赖。
三级缓存与 AOP 的协作流程
关键方法:getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AOP 代理在这里创建!
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
详细流程分析
场景:UserService ↔ OrderService(UserService 需要事务代理)
步骤1:创建 UserService
// 1. 实例化 UserService(原始对象)
Object userService = createBeanInstance("userService");
// 2. 添加到三级缓存
addSingletonFactory("userService", () ->
getEarlyBeanReference("userService", mbd, userService)
);
// 在 getEarlyBeanReference 中:
// AbstractAutoProxyCreator 会检查是否需要创建代理
// 由于 UserService 有 @Transactional,需要创建代理
// 返回的是 UserService 的代理对象,不是原始对象
步骤2:UserService 需要 OrderService
// 开始属性注入
populateBean("userService");
// 发现需要 orderService
getBean("orderService");
步骤3:创建 OrderService
// 1. 实例化 OrderService
Object orderService = createBeanInstance("orderService");
// 2. 添加到三级缓存
addSingletonFactory("orderService", () ->
getEarlyBeanReference("orderService", mbd, orderService)
);
// OrderService 没有 AOP 需求,返回原始对象
步骤4:OrderService 需要 UserService
// OrderService 属性注入时调用 getBean("userService")
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从三级缓存获取 UserService 的 ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get("userService");
if (singletonFactory != null) {
// 调用 getEarlyBeanReference,返回 UserService 的代理对象
Object earlyReference = singletonFactory.getObject();
// earlyReference 是 UserService 的代理对象!
this.earlySingletonObjects.put("userService", earlyReference);
this.singletonFactories.remove("userService");
return earlyReference;
}
}
步骤5:完成创建过程
// OrderService 注入的是 UserService 的代理对象
// OrderService 完成创建,放入一级缓存
// UserService 继续属性注入,注入完整的 OrderService
// UserService 完成初始化
// 注意:这里 UserService 已经是代理对象,不需要再次代理
AbstractAutoProxyCreator 的关键实现
getEarlyBeanReference 方法
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 记录当前Bean需要早期代理
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 创建代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 检查是否已经创建过早期代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果没有创建过早期代理,现在创建
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否需要创建代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用的增强器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
不同 AOP 场景的处理
1. 基于接口的 JDK 动态代理
@Service
public class UserServiceImpl implements UserService {
@Autowired
private OrderService orderService;
@Transactional
@Override
public void createUser() {
// 业务逻辑
}
}
// 创建的代理对象类型:com.sun.proxy.$Proxy123
2. 基于类的 CGLIB 代理
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
public void createUser() {
// 业务逻辑
}
}
// 创建的代理对象类型:UserService$$EnhancerBySpringCGLIB$$123456
3. 多个 AOP 切面的情况
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
@Loggable
@RateLimited
public void createUser() {
// 业务逻辑
}
}
// 代理对象会包含所有切面的逻辑
特殊场景分析
场景1:只有一方需要 AOP 代理
@Component
public class A {
@Autowired
private B b;
@Transactional
public void methodA() {}
}
@Component
public class B {
@Autowired
private A a; // 注入的是 A 的代理对象
public void methodB() {
a.methodA(); // 调用代理方法,事务生效
}
}
处理:B 中注入的是 A 的代理对象,事务正常工作。
场景2:双方都需要 AOP 代理
@Component
public class A {
@Autowired
private B b; // 注入的是 B 的代理对象
@Async
public void methodA() {}
}
@Component
public class B {
@Autowired
private A a; // 注入的是 A 的代理对象
@Transactional
public void methodB() {}
}
处理:双方都通过三级缓存获取对方的代理对象。
场景3:自我注入 + AOP
@Component
public class SelfInjectService {
@Autowired
private SelfInjectService self;
@Transactional
public void externalCall() {
// 外部调用:走代理,事务生效
}
public void internalCall() {
// 内部调用:不走代理,事务不生效
self.externalCall(); // 需要这样调用才能走代理
}
}
配置和调优
1. 控制 AOP 代理创建时机
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AppConfig {
// 启用 CGLIB 代理,暴露代理对象
}
2. 自定义 BeanPostProcessor
@Component
public class CustomBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
// 自定义早期代理逻辑
if (bean instanceof SomeSpecialInterface) {
return createSpecialProxy(bean);
}
return bean;
}
}
问题排查和调试
1. 检查代理对象类型
@Component
public class ProxyChecker {
@Autowired
private ApplicationContext context;
public void checkProxy() {
Object bean = context.getBean("userService");
System.out.println("Bean class: " + bean.getClass());
System.out.println("Is JDK proxy: " + AopUtils.isJdkDynamicProxy(bean));
System.out.println("Is CGLIB proxy: " + AopUtils.isCglibProxy(bean));
System.out.println("Target class: " + AopUtils.getTargetClass(bean));
}
}
2. 调试三级缓存状态
public class CacheDebugger {
public static void debugCache(DefaultSingletonBeanRegistry registry, String beanName) {
System.out.println("=== 三级缓存状态 ===");
System.out.println("一级缓存: " + getField(registry, "singletonObjects").get(beanName));
System.out.println("二级缓存: " + getField(registry, "earlySingletonObjects").get(beanName));
System.out.println("三级缓存: " + getField(registry, "singletonFactories").get(beanName));
}
private static Map getField(Object obj, String fieldName) {
// 反射获取字段值
}
}
最佳实践
1. 避免在构造方法中使用 AOP 功能
@Component
public class ProblematicService {
@Autowired
private AnotherService anotherService;
public ProblematicService() {
// 错误:此时代理对象还未创建
// anotherService.someMethod();
}
@PostConstruct
public void init() {
// 正确:在 @PostConstruct 中使用
anotherService.someMethod();
}
}
2. 合理使用 exposeProxy
@Service
public class TransactionalService {
@Transactional
public void outerMethod() {
// 需要获取当前代理对象来调用内部方法
TransactionalService proxy = (TransactionalService) AopContext.currentProxy();
proxy.innerMethod();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
// 需要新事务
}
}
3. 注意 AOP 的适用范围
// 明确指定切面范围,避免不必要的代理
@Aspect
@Component
public class SpecificAspect {
@Before("execution(* com.example.service.*.*(..)) && " +
"!execution(* com.example.service.*.internal*(..))")
public void beforeAdvice() {
// 只对特定方法生效
}
}
总结
Spring 三级缓存与 AOP 的协同工作机制:
- 时机把握:在 Bean 实例化后立即通过
getEarlyBeanReference创建代理 - 一致性保证:通过
earlyProxyReferences确保不会重复创建代理 - 循环依赖支持:即使存在循环依赖,也能正确注入代理对象
- 透明性:对业务代码完全透明,无需关心代理创建细节
理解这一机制对于排查 AOP 相关问题、优化应用性能以及设计复杂的 Bean 依赖关系都有重要意义。
4️⃣ 参考 4
Spring 三级缓存与 AOP 的深度解析
1. 问题背景:AOP 代理与循环依赖的冲突
当 Bean 需要被 AOP 代理,同时又存在循环依赖时,就产生了复杂的场景:
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 需要 AOP 代理
public void createUser() {
// 业务逻辑
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 需要注入的是 UserService 的代理对象
}
核心问题:
- UserService 需要被 AOP 代理(@Transactional)
- OrderService 依赖 UserService
- 在循环依赖中,需要确保注入的是代理对象而非原始对象
2. 三级缓存如何支持 AOP 代理
2.1 关键方法:getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// AbstractAutoProxyCreator 会在这里创建代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
2.2 AbstractAutoProxyCreator 的实现
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 创建早期代理引用的关键方法
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 包装 Bean,如果需要代理则创建代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 如果已经创建过早期代理,这里就不再重复创建
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 判断是否需要创建代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是基础设施类或应该跳过,则不代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
3. 完整流程分析(AOP + 循环依赖)
3.1 场景设定
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional
public void saveUser() {
System.out.println("Save user");
orderService.createOrder();
}
}
@Service
public class OrderService {
@Autowired
private UserService userService;
public void createOrder() {
System.out.println("Create order");
userService.saveUser(); // 这里需要调用代理方法
}
}
@Aspect
@Component
public class TransactionAspect {
@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Start transaction");
Object result = pjp.proceed();
System.out.println("Commit transaction");
return result;
}
}
3.2 详细执行流程
步骤 1:创建 UserService
// 1. 开始创建 UserService
singletonsCurrentlyInCreation.add("userService");
// 2. 实例化原始对象
UserService userService = new UserService();
// 3. 将 ObjectFactory 放入三级缓存
addSingletonFactory("userService", () -> getEarlyBeanReference("userService", mbd, userService));
步骤 2:UserService 属性注入
// 1. 发现需要注入 OrderService
// 2. 调用 getBean("orderService")
步骤 3:创建 OrderService
// 1. 开始创建 OrderService
singletonsCurrentlyInCreation.add("orderService");
// 2. 实例化原始对象
OrderService orderService = new OrderService();
// 3. 将 ObjectFactory 放入三级缓存
addSingletonFactory("orderService", () -> getEarlyBeanReference("orderService", mbd, orderService));
步骤 4:OrderService 属性注入 - 关键步骤
// 1. 发现需要注入 UserService
// 2. 调用 getBean("userService") - 此时 userService 正在创建
// 3. 从三级缓存获取 UserService 的早期引用
ObjectFactory<?> singletonFactory = singletonFactories.get("userService");
Object earlyReference = singletonFactory.getObject(); // 触发 getEarlyBeanReference
// 4. 在 getEarlyBeanReference 中:
// - AbstractAutoProxyCreator 检测到 @Transactional 注解
// - 创建 UserService 的代理对象:UserService$$EnhancerBySpringCGLIB
// - 返回代理对象而不是原始对象
// 5. 将代理对象放入二级缓存
earlySingletonObjects.put("userService", userServiceProxy);
singletonFactories.remove("userService");
// 6. OrderService 成功注入 UserService 的代理对象
步骤 5:OrderService 完成创建
// OrderService 完成初始化
// 放入一级缓存
addSingleton("orderService", orderService);
步骤 6:UserService 完成创建
// 1. 继续属性注入(此时 OrderService 已可用)
// 2. 进行初始化
// 3. 调用 postProcessAfterInitialization
Object cacheKey = getCacheKey(UserService.class, "userService");
if (!earlyProxyReferences.containsKey(cacheKey)) {
// 因为已经在早期引用中创建过代理,这里不再重复创建
return wrapIfNecessary(userService, "userService", cacheKey);
}
// 4. 将最终的代理对象放入一级缓存
addSingleton("userService", userServiceProxy);
4. 为什么需要三级缓存来处理 AOP?
4.1 两级缓存的问题
如果只有两级缓存(一级 + 二级),会出现以下问题:
// 假设只有两级缓存
public Object getSingleton(String beanName) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 直接从二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 问题:无法在这里创建代理对象!
// 因为缺少 ObjectFactory 机制
}
}
return singletonObject;
}
问题:
- 代理时机不当:需要在 Bean 实例化后就立即创建代理,而不是在需要时才创建
- 资源浪费:即使没有循环依赖,也会提前创建代理对象
- 逻辑复杂:无法处理复杂的代理逻辑
4.2 三级缓存的优势
// 三级缓存通过 ObjectFactory 延迟创建
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 只有在真正需要早期引用时才创建代理
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 按需创建:有循环依赖才创建早期代理
singletonObject = singletonFactory.getObject();
}
优势:
- 延迟创建:只有存在循环依赖时才创建早期代理
- 逻辑分离:代理创建逻辑与 Bean 创建逻辑解耦
- 一致性保证:确保所有依赖方都使用相同的代理对象
5. 特殊情况处理
5.1 多个 Bean 依赖同一个被代理的 Bean
@Service
public class ServiceA {
@Autowired
private CommonService commonService; // 需要代理
}
@Service
public class ServiceB {
@Autowired
private CommonService commonService; // 需要代理
}
@Service
@Transactional
public class CommonService {
// 被 AOP 代理
}
处理机制:
- 第一次从三级缓存获取时创建代理
- 后续获取都从二级缓存拿到相同的代理对象
- 确保所有依赖方使用同一个代理实例
5.2 嵌套代理场景
@Service
public class OuterService {
@Autowired
private InnerService innerService; // 也需要代理
@Transactional
public void outerMethod() {
innerService.innerMethod();
}
}
@Service
@Transactional
public class InnerService {
public void innerMethod() {
// 业务逻辑
}
}
处理流程:
- OuterService 创建 → 需要 InnerService
- InnerService 创建 → 放入三级缓存(包含代理工厂)
- OuterService 获取 InnerService → 通过三级缓存得到代理对象
- 两个 Service 都正确获得代理,事务嵌套正常工作
6. 源码调试技巧
6.1 关键断点位置
// 1. 三级缓存相关
DefaultSingletonBeanRegistry.getSingleton(String, boolean)
DefaultSingletonBeanRegistry.addSingletonFactory(String, ObjectFactory)
DefaultSingletonBeanRegistry.getEarlyBeanReference(String, RootBeanDefinition, Object)
// 2. AOP 代理相关
AbstractAutoProxyCreator.getEarlyBeanReference(Object, String)
AbstractAutoProxyCreator.wrapIfNecessary(Object, String, Object)
AbstractAutoProxyCreator.postProcessAfterInitialization(Object, String)
// 3. Bean 创建流程
AbstractAutowireCapableBeanFactory.doCreateBean(String, RootBeanDefinition, Object[])
AbstractAutowireCapableBeanFactory.createBeanInstance(String, RootBeanDefinition, Object[])
AbstractAutowireCapableBeanFactory.populateBean(String, RootBeanDefinition, BeanWrapper)
6.2 调试配置
// 创建测试类观察代理创建过程
public class CircularDependencyDebug {
@Autowired
private ApplicationContext applicationContext;
@PostConstruct
public void debugProxies() {
// 检查 UserService 是否是代理
UserService userService = applicationContext.getBean(UserService.class);
System.out.println("UserService class: " + userService.getClass());
System.out.println("Is JDK proxy: " + AopUtils.isJdkDynamicProxy(userService));
System.out.println("Is CGLIB proxy: " + AopUtils.isCglibProxy(userService));
// 检查 OrderService 中注入的 UserService
OrderService orderService = applicationContext.getBean(OrderService.class);
Field userServiceField = ReflectionUtils.findField(OrderService.class, "userService");
ReflectionUtils.makeAccessible(userServiceField);
Object injectedUserService = ReflectionUtils.getField(userServiceField, orderService);
System.out.println("Injected UserService class: " + injectedUserService.getClass());
}
}
7. 最佳实践和注意事项
7.1 推荐做法
// 1. 使用接口 + JDK 动态代理(更清晰)
public interface UserService {
void saveUser();
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private OrderService orderService;
@Transactional
@Override
public void saveUser() {
// 实现
}
}
// 2. 避免在 @PostConstruct 方法中调用代理方法
@Service
public class OrderService {
@Autowired
private UserService userService;
@PostConstruct
public void init() {
// 不推荐:此时代理可能还未完全准备好
// userService.saveUser();
}
}
7.2 常见陷阱
// 陷阱 1:自调用问题
@Service
public class ProblemService {
@Transactional
public void methodA() {
methodB(); // 自调用,AOP 代理失效!
}
@Transactional
public void methodB() {
// 这个方法不会在事务中执行
}
}
// 陷阱 2:final 方法无法被 CGLIB 代理
@Service
public final class FinalService { // final 类无法被代理
@Transactional
public final void finalMethod() { // final 方法无法被代理
// 事务注解无效
}
}
8. 总结
Spring 三级缓存与 AOP 的协作体现了框架设计的精妙之处:
核心机制:
- 三级缓存:提供早期引用创建的基础设施
- ObjectFactory:延迟创建,支持按需代理
- getEarlyBeanReference:AOP 代理的接入点
设计价值:
- 解耦:Bean 创建与代理创建逻辑分离
- 性能:只有循环依赖时才创建早期代理
- 一致性:确保所有依赖方使用相同的代理实例
实践启示:
- 理解三级缓存机制有助于诊断复杂的循环依赖问题
- 掌握 AOP 代理时机可以避免自调用等常见陷阱
- 合理设计 Bean 依赖关系,减少复杂的循环依赖场景
5️⃣ 参考 5
Spring 三级缓存与 AOP 的深度解析
1. AOP 代理与循环依赖的挑战
1.1 核心问题 当 Bean 需要 AOP 代理且存在循环依赖时,Spring 需要确保:
- 循环依赖注入的是代理对象而非原始对象
- 代理对象在整个应用生命周期中保持一致
- 避免重复创建代理对象
1.2 问题示例
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Transactional // 需要 AOP 代理
public void createUser() {
// 事务方法
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 需要注入代理对象!
public void createOrder() {
userService.createUser(); // 必须调用代理对象以保证事务生效
}
}
2. 三级缓存如何支持 AOP
2.1 关键方法:getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp =
(SmartInstantiationAwareBeanPostProcessor) bp;
// 关键:在这里决定是否创建代理对象
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
2.2 AnnotationAwareAspectJAutoProxyCreator 的作用
public class AnnotationAwareAspectJAutoProxyCreator
extends AbstractAutoProxyCreator
implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 提前创建代理对象
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 检查是否已经创建过早期代理
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果没有创建过早期代理,现在创建
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
}
3. AOP 代理的完整创建流程
3.1 包含 AOP 的循环依赖解决流程
// UserService 创建流程(需要 AOP 代理)
1. 开始创建 UserService
2. 实例化 UserService(原始对象)
3. 添加到三级缓存:
addSingletonFactory("userService", () -> getEarlyBeanReference("userService", mbd, bean))
// 此时会调用 AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference()
// 如果需要代理,返回代理对象;否则返回原始对象
4. 属性填充:发现需要 OrderService
5. 开始创建 OrderService
// OrderService 创建流程
6. 实例化 OrderService
7. 添加到三级缓存
8. 属性填充:发现需要 UserService
9. 获取 UserService:
- 三级缓存:找到 UserService 的 ObjectFactory
- 调用 getObject() → getEarlyBeanReference()
- 由于 UserService 有 @Transactional,返回代理对象
- 代理对象放入二级缓存
10. OrderService 完成初始化,放入一级缓存
// 回到 UserService
11. 属性填充完成(注入了 OrderService)
12. 初始化:调用 postProcessAfterInitialization
- 检查 earlyProxyReferences,发现已经创建过代理,直接返回
13. UserService(代理对象)放入一级缓存
3.2 流程图解
UserService 创建流程:
1. 实例化原始对象
2. 添加到三级缓存 + 创建早期代理引用
3. 属性填充 → 需要 OrderService
↓
OrderService 创建流程:
4. 实例化原始对象
5. 添加到三级缓存
6. 属性填充 → 需要 UserService
↓
获取 UserService:
7. 三级缓存 → ObjectFactory.getObject()
8. 调用 getEarlyBeanReference() → 返回代理对象
9. 代理对象放入二级缓存
↓
OrderService 继续:
10. 完成属性填充和初始化
11. 放入一级缓存
↓
UserService 继续:
12. 完成属性填充
13. 初始化 → 检查已创建代理,直接使用
14. 代理对象放入一级缓存
4. 源码深度分析
4.1 AbstractAutoProxyCreator 的关键实现
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
// 保存早期代理引用的缓存
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
// 生成缓存键
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 记录原始对象
this.earlyProxyReferences.put(cacheKey, bean);
// 包装为代理(如果需要)
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
// 检查是否已经处理过早期引用
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 如果没有,现在创建代理
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 检查是否需要代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是基础设施类或应该跳过,则不代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取适用的通知
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
4.2 代理创建决策流程
// 判断是否需要创建代理的决策逻辑
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 1. 检查缓存
if (this.advisedBeans.containsKey(cacheKey)) {
return bean;
}
// 2. 检查基础设施类
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 3. 查找适用的 Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 4. 决定是否创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
5. 不同类型的 AOP 代理处理
5.1 JDK 动态代理 vs CGLIB
protected Object createProxy(Class<?> beanClass, String beanName,
Object[] specificInterceptors, TargetSource targetSource) {
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 决定使用 JDK 代理还是 CGLIB
if (!proxyFactory.isProxyTargetClass()) {
// 检查接口决定
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
// 评估接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 添加 Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 自定义代理
customizeProxyFactory(proxyFactory);
// 创建代理
return proxyFactory.getProxy(getProxyClassLoader());
}
5.2 基于注解的代理决策
// 检查类是否需要代理的典型条件
private boolean shouldCreateProxy(Class<?> beanClass, String beanName) {
// 1. 检查 @Transactional 注解
if (isTransactionManagementEnabled() &&
findAnnotation(beanClass, Transactional.class) != null) {
return true;
}
// 2. 检查 @Async 注解
if (hasAsyncMethods(beanClass)) {
return true;
}
// 3. 检查自定义 AOP 注解
if (hasMatchingAdvisors(beanClass)) {
return true;
}
// 4. 检查配置的切点表达式
if (pointcutMatches(beanClass, beanName)) {
return true;
}
return false;
}
6. 特殊情况处理
6.1 @Async 方法的特殊处理
@Service
public class UserService {
@Autowired
private OrderService orderService;
@Async // 需要代理
public void asyncProcess() {
// 异步方法
}
}
@Service
public class OrderService {
@Autowired
private UserService userService; // 需要注入代理对象
public void processOrder() {
userService.asyncProcess(); // 必须调用代理对象才能异步执行
}
}
处理机制:
@Async通过AsyncAnnotationBeanPostProcessor处理- 在
getEarlyBeanReference中创建代理 - 确保循环依赖中注入的是代理对象
6.2 多层代理场景
@Service
public class ComplexService {
@Autowired
private AnotherService anotherService;
@Transactional
@Async
public void complexOperation() {
// 既需要事务又需要异步
}
}
处理流程:
- 实例化原始对象
getEarlyBeanReference中按顺序应用 BeanPostProcessor- 可能创建多层代理包装
- 确保最终代理对象包含所有必要的功能
7. 调试与问题排查
7.1 代理对象检测
@Component
public class ProxyDetection implements ApplicationRunner {
@Autowired
private ApplicationContext context;
@Override
public void run(ApplicationArguments args) {
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
Object bean = context.getBean(beanName);
detectProxyType(beanName, bean);
}
}
private void detectProxyType(String beanName, Object bean) {
Class<?> beanClass = bean.getClass();
// 检测代理类型
if (isJdkDynamicProxy(bean)) {
System.out.println(beanName + " 是 JDK 动态代理");
} else if (isCglibProxy(bean)) {
System.out.println(beanName + " 是 CGLIB 代理");
} else {
System.out.println(beanName + " 是原始对象");
}
// 显示代理的目标类
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
if (targetClass != beanClass) {
System.out.println(beanName + " 的原始类: " + targetClass.getName());
}
}
private boolean isJdkDynamicProxy(Object bean) {
return Proxy.isProxyClass(bean.getClass());
}
private boolean isCglibProxy(Object bean) {
return bean.getClass().getName().contains("$$EnhancerBySpringCGLIB$$");
}
}
7.2 三级缓存状态监控
@Component
public class CacheMonitor {
@Autowired
private AbstractApplicationContext context;
public void monitorCacheDuringCreation(String beanName) {
DefaultSingletonBeanRegistry registry =
(DefaultSingletonBeanRegistry) context.getBeanFactory();
// 监控特定 Bean 的创建过程
try {
Object bean = context.getBean(beanName);
System.out.println("Bean " + beanName + " 创建完成");
} catch (Exception e) {
System.err.println("Bean " + beanName + " 创建失败: " + e.getMessage());
}
printCacheStatus(registry);
}
private void printCacheStatus(DefaultSingletonBeanRegistry registry) {
try {
// 通过反射获取缓存状态
Field singletonObjectsField =
DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
singletonObjectsField.setAccessible(true);
Map<?, ?> singletonObjects = (Map<?, ?>) singletonObjectsField.get(registry);
Field earlySingletonObjectsField =
DefaultSingletonBeanRegistry.class.getDeclaredField("earlySingletonObjects");
earlySingletonObjectsField.setAccessible(true);
Map<?, ?> earlySingletonObjects = (Map<?, ?>) earlySingletonObjectsField.get(registry);
Field singletonFactoriesField =
DefaultSingletonBeanRegistry.class.getDeclaredField("singletonFactories");
singletonFactoriesField.setAccessible(true);
Map<?, ?> singletonFactories = (Map<?, ?>) singletonFactoriesField.get(registry);
System.out.println("一级缓存大小: " + singletonObjects.size());
System.out.println("二级缓存大小: " + earlySingletonObjects.size());
System.out.println("三级缓存大小: " + singletonFactories.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
8. 性能优化与最佳实践
8.1 代理创建优化
@Configuration
@EnableAspectJAutoProxy(
proxyTargetClass = true, // 强制使用 CGLIB
exposeProxy = true // 暴露代理对象
)
public class AopConfig {
// AOP 配置
}
8.2 避免不必要的代理
@Service
public class NoProxyService {
// 没有注解,不需要代理
public void normalMethod() {
// 普通方法
}
}
// 在配置中明确排除
@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration {
@Bean
public static BeanFactoryPostProcessor aopExclusion() {
return beanFactory -> {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
ConfigurableListableBeanFactory configurableFactory =
(ConfigurableListableBeanFactory) beanFactory;
// 排除不需要代理的 Bean
configurableFactory.addBeanPostProcessor(new NoProxyPostProcessor());
}
};
}
static class NoProxyPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanName.contains("NoProxy")) {
// 标记为不需要代理
return new Object();
}
return null;
}
}
}
9. 常见问题与解决方案
9.1 代理对象方法调用问题
@Service
public class ProblemService {
@Autowired
private AnotherService anotherService;
@Transactional
public void outerMethod() {
// 这个会走代理,事务生效
innerMethod(); // 问题:这个不会走代理,事务不生效!
}
@Transactional
public void innerMethod() {
// 事务不会生效
}
// 解决方案1:自我注入
@Autowired
private ProblemService self;
public void solution1() {
self.innerMethod(); // 通过代理对象调用
}
// 解决方案2:使用 AopContext
public void solution2() {
((ProblemService) AopContext.currentProxy()).innerMethod();
}
}
9.2 循环依赖 + AOP 的启动失败
// 错误配置导致的问题
@Configuration
@EnableAspectJAutoProxy(exposeProxy = false) // 没有暴露代理
public class ProblemConfig {
}
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
@Transactional
public void methodA() {}
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA; // 循环依赖
public void methodB() {
// 需要调用代理方法
serviceA.methodA();
}
}
解决方案:
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true) // 暴露代理
public class FixedConfig {
}
10. 总结
Spring 三级缓存与 AOP 的协同工作机制:
核心机制:
- 提前暴露代理:在
getEarlyBeanReference中创建早期代理对象 - 避免重复代理:通过
earlyProxyReferences缓存避免重复创建 - 代理一致性:确保循环依赖中注入的是正确的代理对象
关键时机:
- 三级缓存阶段:
getEarlyBeanReference()创建早期代理 - 初始化后阶段:
postProcessAfterInitialization()检查并补充代理
设计优势:
- 解决循环依赖:通过三级缓存打破依赖循环
- 支持 AOP 功能:确保代理对象的功能完整性
- 性能优化:避免重复创建代理对象
- 一致性保证:整个应用中使用相同的代理实例
实践建议:
- 理解代理机制对于调试复杂依赖关系至关重要
- 合理使用
@Lazy避免不必要的循环依赖 - 在需要时正确配置
exposeProxy = true - 监控代理创建过程以优化性能
这种精妙的机制使得 Spring 能够同时支持复杂的依赖关系和强大的 AOP 功能,是现代企业级应用开发的重要基础。
6️⃣ 参考 6
Spring 三级缓存与 AOP 的深度解析
一、Spring 三级缓存:解决循环依赖的核心机制 Spring 的三级缓存是为解决单例 Bean 的循环依赖问题而设计的,其本质是通过“提前暴露”尚未完全初始化的 Bean 实例来打破循环依赖链。三级缓存的结构如下:
| 缓存层级 | 存储内容 | 作用 |
|---|---|---|
| 一级缓存(singletonObjects) | 完全初始化完成的单例 Bean | 直接获取成熟 Bean,避免重复创建 |
| 二级缓存(earlySingletonObjects) | 提前暴露的“半成品”Bean(已实例化但未属性注入/初始化) | 解决循环依赖时,其他 Bean 可注入此半成品 |
| 三级缓存(singletonFactories) | 存储“工厂方法”(ObjectFactory) | 通过工厂动态生成半成品 Bean(支持 AOP 代理的延迟生成),是解决循环依赖的关键 |
工作流程示例(以 A 依赖 B,B 依赖 A 为例):
- 创建 A 时,发现需要注入 B,此时触发 B 的创建;
- 创建 B 时,发现需要注入 A,此时从三级缓存中获取 A 的工厂方法,生成 A 的代理对象(若 A 需 AOP)并放入二级缓存;
- B 完成初始化后放入一级缓存,同时 A 继续完成属性注入(从二级缓存获取 B),最终 A 也完成初始化。
关键点:三级缓存通过 ObjectFactory 延迟生成代理对象,确保 AOP 代理在循环依赖场景下仍能正确应用。
二、AOP(面向切面编程):横切关注点的模块化 AOP 的核心思想是将业务逻辑与通用功能(如日志、事务、安全)分离,通过代理机制在目标方法执行前后插入增强逻辑。Spring AOP 的实现依赖两种代理方式:
| 代理方式 | 适用场景 | 原理 |
|---|---|---|
| JDK 动态代理 | 目标类实现接口 | 基于 Java 反射生成代理类,需实现 InvocationHandler 接口 |
| CGLIB 动态代理 | 目标类未实现接口 | 通过字节码生成技术(ASM)创建目标类的子类,需添加 MethodInterceptor |
AOP 核心概念:
- 切面(Aspect):增强逻辑 + 切点的组合(如
@Aspect注解的类); - 切点(Pointcut):定义在哪些方法上应用增强(如
@Before("execution(* com.example.service.*.*(..))")); - 通知(Advice):增强的具体行为(如前置通知、环绕通知);
- 织入(Weaving):将切面逻辑合并到目标对象的过程(Spring 在 Bean 初始化时完成)。
三、三级缓存与 AOP 的协同关系
在循环依赖场景下,若目标 Bean 需要 AOP 代理(如被 @Transactional 或 @Aspect 修饰),Spring 会通过三级缓存确保代理对象的正确生成:
- 三级缓存存储工厂方法:当 Bean 实例化后(但未初始化),Spring 将其包装为
ObjectFactory存入三级缓存。若该 Bean 需要 AOP,工厂方法会动态生成代理对象; - 二级缓存缓存半成品:当其他 Bean 依赖此 Bean 时,通过工厂方法生成代理对象并存入二级缓存,供循环依赖的另一方使用;
- 一级缓存存储最终对象:Bean 完成初始化(包括属性注入、AOP 代理生成)后,移入一级缓存。
示例场景:
- 若 ServiceA 依赖 ServiceB,且 ServiceB 需事务管理(AOP 代理),则:
- 创建 ServiceB 时,其原始对象存入三级缓存(工厂方法);
- 当 ServiceA 需要注入 ServiceB 时,从三级缓存的工厂方法中生成 ServiceB 的代理对象(包含事务逻辑)并存入二级缓存;
- ServiceA 完成注入后,ServiceB 继续初始化并最终进入一级缓存。
注意事项:
- 原型模式(prototype) 的 Bean 不支持循环依赖,因每次获取都是新实例;
- 多例 Bean 的循环依赖需通过
@Lazy延迟加载或重构设计避免; - AOP 代理的生成时机在 Bean 的初始化阶段(
postProcessAfterInitialization),确保代理对象包含所有增强逻辑。
四、总结
- 三级缓存是 Spring 解决单例 Bean 循环依赖的核心设计,通过“半成品”对象的提前暴露打破依赖循环;
- AOP 通过代理模式实现横切关注点的模块化,与三级缓存协同确保在循环依赖场景下代理对象的正确生成;
- 开发者需理解两者的工作原理,以优化 Bean 的设计(如避免不必要的循环依赖)和 AOP 的使用(如切点定义的精准性)。
7️⃣ 参考 7
Spring三级缓存与AOP的关系
Spring的三级缓存机制不仅解决了循环依赖问题,还与AOP(面向切面编程)紧密相关。理解它们之间的关系对深入掌握Spring框架至关重要。
三级缓存与AOP的核心关联
Spring的三级缓存设计中,三级缓存(singletonFactories) 是与AOP直接相关的关键组件:
-
三级缓存(singletonFactories)的作用
- 存储
ObjectFactory函数式接口 - 通过
getObject()方法生成代理对象 - 专门用于解决AOP代理与循环依赖的双重问题
- 存储
-
AOP代理的特殊处理
protected Object getEarlyBeanReference(String beanName, Object bean) { // 若有AOP配置,在此处生成代理对象 return applyBeanPostProcessorsBeforeInstantiation(bean.getClass(), beanName); }- 在Bean创建过程中,如果存在AOP配置,Spring会在
getEarlyBeanReference方法中生成代理对象 - 这个代理对象会被放入二级缓存(earlySingletonObjects)中
- 在Bean创建过程中,如果存在AOP配置,Spring会在
为什么需要三级缓存来支持AOP?
问题背景 如果只用两级缓存(一级和二级)来处理循环依赖,会遇到以下问题:
-
代理对象的生成时机问题
- 如果在二级缓存中直接存储代理对象,那么当Bean完成初始化后,二级缓存中的代理对象与最终的Bean对象不一致
- 导致AOP代理失效或产生不一致的状态
-
AOP与循环依赖的双重需求
- 需要提前暴露"早期Bean"解决循环依赖
- 需要确保暴露的Bean是AOP增强后的代理对象
三级缓存的解决方案 三级缓存(singletonFactories)提供了一个"工厂",解决了上述问题:
-
在三级缓存中存储ObjectFactory
- 保存的是一个可以生成代理对象的工厂方法
- 可以在需要时(如循环依赖场景)生成代理对象
-
工作流程
- 创建Bean时,先将ObjectFactory放入三级缓存
- 当需要获取Bean时,从三级缓存中获取ObjectFactory
- 通过ObjectFactory生成代理对象
- 将生成的代理对象放入二级缓存
- 通过二级缓存提供给依赖方
三级缓存与AOP的协同工作流程
以A依赖B,B依赖A,且A有AOP代理的场景为例:
-
创建A:
- 实例化A(A是半成品)
- 创建ObjectFactory,放入三级缓存(singletonFactories)
-
A需要注入B:
- 开始创建B
- B需要注入A,从三级缓存获取A的ObjectFactory
- 通过ObjectFactory生成A的早期代理对象(已应用AOP)
- 将生成的代理对象放入二级缓存(earlySingletonObjects)
-
B完成初始化:
- B完成属性注入和初始化
- B放入一级缓存(singletonObjects)
-
A继续完成:
- A从二级缓存获取到B
- A完成属性注入和初始化
- A放入一级缓存
- 从三级缓存移除A的ObjectFactory
为什么二级缓存(earlySingletonObjects)是必需的?
从知识库[1]中可以找到关键解释:
"二级缓存(earlySingletonObjects):存储已实例化但未初始化的"早期引用",用于解决AOP代理问题"
二级缓存的作用是:
- 存储"已生成AOP代理"的早期Bean
- 避免在三级缓存中存储代理对象,而是通过工厂方式生成
如果不用二级缓存,而直接将代理对象放入三级缓存,会导致:
- 无法区分原始Bean和代理Bean
- 在Bean初始化完成后,二级缓存中的代理对象与最终Bean不一致
三级缓存与AOP的总结
-
三级缓存的核心目的:
- 解决循环依赖问题
- 支持AOP代理的提前暴露
-
三级缓存与AOP的关系:
- 三级缓存(singletonFactories)是AOP代理的"工厂"
- 二级缓存(earlySingletonObjects)存储的是已应用AOP的代理对象
- 一级缓存(singletonObjects)存储的是最终的、完整的Bean
-
为什么必须使用三级缓存:
"不用3级缓存,那么对象的初始化就要提到实例化过程中,会破坏spring的整体流程"
-
重要限制:
- 三级缓存仅适用于Singleton作用域的Bean
- 无法解决构造器注入的循环依赖
- 无法解决原型Bean的循环依赖
实际应用中的重要提示
- AOP与循环依赖的结合:当Bean同时有AOP配置和循环依赖时,三级缓存机制确保了AOP代理能正确应用
- 避免过度依赖:虽然Spring能解决循环依赖,但循环依赖通常表明设计问题,应尽量避免
- AOP代理时机:AOP代理在Bean创建的"早期"(实例化后、属性注入前)完成,确保能正确处理循环依赖
理解Spring三级缓存与AOP的关系,有助于我们更好地设计应用结构,避免不必要的循环依赖,同时能更深入地掌握Spring IoC容器的工作原理。
8️⃣ 参考 8
在Spring中,三级缓存与AOP(面向切面编程)的结合是解决循环依赖场景下代理对象一致性的关键。AOP的核心是通过动态代理(JDK代理或CGLIB)为目标Bean生成代理对象,而循环依赖可能导致“注入的对象”与“最终容器中的对象”不一致(例如注入原始对象,最终却用代理对象)。三级缓存通过巧妙的设计,确保了循环依赖中注入的是正确的代理对象。
一、AOP在Bean创建中的常规流程 在无循环依赖的情况下,AOP代理对象的创建时机是:
- 先实例化目标Bean(原始对象);
- 执行属性注入和初始化方法(如
@PostConstruct); - 若Bean需要被AOP增强(如被
@Transactional、@Async等注解标记),则通过AnnotationAwareAspectJAutoProxyCreator等后置处理器生成代理对象; - 最终将代理对象放入一级缓存(
singletonObjects),供后续使用。
此时,Bean的原始对象不会被暴露,容器中只有代理对象,不存在一致性问题。
二、循环依赖下AOP的问题:为什么需要三级缓存? 若存在循环依赖(如A依赖B,B依赖A),且A需要被AOP代理,直接使用“原始对象提前暴露”会导致矛盾:
- 若提前暴露A的原始对象,B会注入原始A,但最终容器中的A是代理对象,导致B依赖的A与容器中的A不一致(一个是原始对象,一个是代理对象);
- 若提前暴露A的代理对象,又会导致代理对象生成过早(可能在原始对象初始化完成前),而AOP代理可能依赖原始对象的初始化结果(如初始化方法中设置的属性)。
三、三级缓存如何解决AOP+循环依赖的一致性问题?
三级缓存的核心是通过singletonFactories(三级缓存)存储的ObjectFactory实现**“延迟生成代理对象”**,仅在循环依赖发生时才触发代理创建,既保证注入的是代理对象,又避免代理生成过早。
具体流程(以A需要AOP代理,A依赖B,B依赖A为例):
-
创建A的原始对象:
Spring实例化A(生成原始对象),此时A尚未注入属性、未执行初始化方法,也未生成代理。 -
将A的工厂放入三级缓存:
向singletonFactories中存入A的ObjectFactory,其核心逻辑(简化)为:() -> { // 若A需要AOP代理,则生成代理对象;否则返回原始对象 return getEarlyBeanReference(beanName, mbd, originalA); }其中,
getEarlyBeanReference会触发AOP代理创建(若需要),但这个过程延迟到“被依赖时”执行。 -
A依赖B,触发B的创建:
B实例化后,在注入属性时发现依赖A,开始查找A。 -
B查找A时触发代理生成:
- 查找顺序:一级缓存(无,A未完成)→ 二级缓存(无)→ 三级缓存(存在A的工厂)。
- 调用A的
ObjectFactory,执行getEarlyBeanReference:若A需要代理,则生成A的代理对象(此时A的原始对象可能尚未完成初始化,但AOP代理仅依赖原始对象的引用,不依赖初始化结果)。 - 将生成的A的代理对象从三级缓存移至二级缓存(
earlySingletonObjects),标记为“提前暴露的早期代理对象”。
-
B注入A的代理对象并完成创建:
B将A的代理对象注入后,完成自身的属性注入和初始化,最终以完整状态放入一级缓存。 -
A完成创建,统一代理对象:
A从一级缓存获取B并注入,随后执行自身的初始化方法。由于A的代理对象已在二级缓存中,A最终会将该代理对象放入一级缓存(覆盖或替换),确保容器中最终的A是代理对象,且与B注入的A是同一个代理对象。
四、关键:三级缓存避免了“代理对象过早生成” 若没有三级缓存,仅用二级缓存直接存储原始对象或代理对象,会有两个问题:
- 若二级缓存存原始对象:循环依赖时B注入原始对象,最终A是代理对象,导致不一致;
- 若二级缓存存代理对象:需在A实例化后立即生成代理(不延迟),但此时A的初始化方法尚未执行,代理可能依赖初始化后的状态(如某些属性),导致代理逻辑错误。
三级缓存的ObjectFactory通过“延迟生成代理”解决了这一问题:仅当循环依赖发生时(B需要A时),才生成代理对象,此时既保证了B注入的是代理对象,又避免了代理生成过早(A的初始化方法可正常执行)。
五、总结 三级缓存与AOP的协同是Spring处理循环依赖的核心设计:
- AOP需要代理对象:确保容器中最终使用的是代理对象;
- 循环依赖需要提前暴露对象:打破“先有鸡还是先有蛋”的依赖链;
- 三级缓存的工厂实现了延迟代理:仅在循环依赖发生时生成代理,既保证了注入对象的一致性(代理对象),又避免了代理生成过早导致的问题。
简言之,三级缓存是Spring在“循环依赖”和“AOP代理”两个约束下找到的最优解,确保了Bean的正确创建和依赖注入。
9️⃣ 参考 9
把「三级缓存」与「AOP」串起来,只需要记住一句话:
三级缓存中的 ObjectFactory 是唯一合法“提前制造代理”的口子,既打破了循环依赖,又保证了 AOP 代理的生命周期一致性。
下面把源码级链路拆开,告诉你为什么“少一层缓存就无法同时满足循环依赖 + AOP”。
- 代理本该在哪诞生?
Spring AOP 的入口在 AbstractAutoProxyCreator#postProcessAfterInitialization
也就是 初始化阶段结束 之后才包装出代理。
// 正常无循环依赖时
instantiate() → populate() → initialize() → BeanPostProcessor → 代理对象
但如果出现循环依赖,别人必须在「populate 阶段」就拿到你的引用;
此时你还没走到 initialize(),正常的 BeanPostProcessor 根本来不及给你包代理。
于是 Spring 做了“提前代理”的妥协。
- 三级缓存如何兼顾“提前”与“合规”
关键代码在 DefaultSingletonBeanRegistry#addSingletonFactory:
// 实例化完成后、populate 之前,Spring 把下面这个工厂放进第三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference 一路调到 AbstractAutoProxyCreator,
它在这里先判断是否需要代理,需要就立刻创建,并缓存结果,保证后续不会重复创建。
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey); // 真正生成代理
}
流程要点
- 只有发生循环依赖,三级缓存的
ObjectFactory才会被调用; - 代理提前创建后,标记已处理,等到真正
initialize()阶段不会再重复代理; - 最终放入一级缓存的是 同一个代理对象,保证全局唯一。
- 为什么二级缓存不够?
二级缓存只能存“裸对象”或“已代理对象”。
如果把它提前放到二级缓存,就必须在 实例化之后立即决定是否代理,
这会打乱 Spring「初始化后再代理」的设计,也可能导致重复代理或遗漏切面。
三级缓存用“工厂”把决策 + 创建延迟到真正被引用那一刻,既安全又合规。
- 一张图看清时间线
无循环依赖
┌────────────┐
│instantiate │
└────┬───────┘
│populate
▼
┌────────────┐
│initialize │←───BeanPostProcessor───► 代理
└────┬───────┘
▼
┌────────────┐
│ 成品 Bean │
└────────────┘
有循环依赖(提前拿引用)
┌────────────┐
│instantiate │
└────┬───────┘
│ 把 ObjectFactory 放入三级缓存
▼
┌──────────────────────┐
│populate 需要 B,B 需要 A│
└────┬─────────────────┘
│调用工厂→getEarlyBeanReference
▼
┌────────────┐
│ 提前代理对象 │←───仅此时创建
└────┬───────┘
│继续 populate/initialize
▼
┌────────────┐
│ 成品代理 Bean(同一对象)│
└────────────┘
- 结论速记
- 第三级缓存 ≈ “提前 AOP 的安全阀门”
- 没有它,要么循环依赖爆掉,要么 AOP 生命周期错乱
- 提前代理仅在被引用时才触发,且只触发一次,后续流程仍按正常生命周期走
想再深入可以给你贴 getSingleton(String, boolean) 的源码逐行注释,或者演示一个 DEBUG 日志,看代理对象何时出现。
🔟 参考 10
Spring三级缓存与AOP的交互是框架解决循环依赖的核心机制,其原理和关系如下:
一、三级缓存的作用
-
singletonObjects(一级缓存)
存放完全初始化完成的Bean,可直接使用。
公式: -
earlySingletonObjects(二级缓存)
存放原始对象(未填充属性),用于临时暴露循环依赖中的早期引用。
公式: -
singletonFactories(三级缓存)
存放ObjectFactory工厂对象,核心解决AOP代理问题:// 伪代码:工厂生成代理对象 objectFactory.getObject() -> { if (需AOP代理) return Proxy(bean); else return bean; }
二、三级缓存与AOP的协作流程
以循环依赖 A→B→A 且 A 需AOP代理为例:
-
实例化A
- 创建A的原始对象
A_raw - 将
ObjectFactory存入三级缓存(而非原始对象)
引用[5]:缓存工厂对象解决循环依赖
- 创建A的原始对象
-
填充A的属性(需注入B)
- 触发B的创建,B同样需要注入A
-
B从缓存获取A
- 一级缓存:无 → 二级缓存:无 → 三级缓存命中
- 调用
ObjectFactory.getObject()- 若A需代理 → 动态生成代理对象
A_proxy - 否则返回
A_raw
引用[2]:三级缓存确保返回代理对象
- 若A需代理 → 动态生成代理对象
-
B完成初始化
- 将B注入A,继续初始化A
- AOP代理时机:在A初始化完成后生成
A_proxy,移入一级缓存
引用[3]:ObjectFactory实现AOP无缝集成
🔑 关键点:三级缓存的
ObjectFactory延迟了代理决策,避免提前返回原始对象导致注入不一致。
三、为何必须三级缓存?二级缓存的缺陷 若只用二级缓存:
- 存入
A_raw到二级缓存 - B注入
A_raw(原始对象) - A初始化完成后生成
A_proxy
→ 系统中存在两个A对象:- B持有
A_raw(已注入不可变) - 容器使用
A_proxy
→ 严重不一致!
引用[4]:二级缓存无法解决代理冲突
- B持有
四、应用场景
- 循环依赖+动态代理
- Spring AOP、
@Async等基于代理的扩展
- Spring AOP、
- 延迟代理生成
- 避免过早创建代理对象(如依赖未注入)
- 框架扩展性
ObjectFactory抽象允许插入自定义逻辑
引用[3]:平衡功能正确性与扩展能力
总结
| 缓存层级 | 存储内容 | 解决的核心问题 |
|---|---|---|
| 一级缓存 | 完整Bean | 提供可用实例 |
| 二级缓存 | 原始Bean | 临时暴露循环引用 |
| 三级缓存(关键) | ObjectFactory | 动态代理与循环依赖的兼容 |
三级缓存通过工厂模式解耦实例化与代理时机,确保: 这种设计体现了Spring容器在复杂场景下的架构智慧。
相关问题
- 如果Bean同时存在构造器循环依赖和AOP代理,Spring如何处理?
- 如何通过代码验证三级缓存在AOP场景下的作用?
- 为什么
@Lazy注解可以解决某些循环依赖问题? - Spring的三级缓存机制在非单例Bean中是否生效?为什么?
- 如何自定义
ObjectFactory实现特定类型的代理逻辑?
参考资料:
: AOP代理对象与三级缓存的关系
: 三级缓存确保返回代理对象
: ObjectFactory实现扩展集成
: 二级缓存的局限性
: 三级缓存的分层定义
🤔 参考 11
Spring 的三级缓存机制与其 AOP 代理功能的协同工作是框架解决单例 Bean 循环依赖的核心设计。它通过巧妙的“延迟暴露”和“提前代理”策略,确保了在复杂依赖场景下功能的正确性与一致性。
为了让你快速建立整体概念,我们先通过一个表格和一张图来俯瞰其核心结构和流程。
📦 三级缓存与 AOP 的协作
三级缓存各自存储不同状态的 Bean,其分工明确,协同解决循环依赖与 AOP 代理的协同问题。
| 缓存层级 | 源码中的名称 | 存储内容 | 核心作用 |
|---|---|---|---|
| 一级缓存 | singletonObjects | 完全初始化完成的单例 Bean | 提供最终可用的 Bean,是正式的“单例池” |
| 二级缓存 | earlySingletonObjects | 早期暴露的 Bean(已实例化,但未完成初始化) | 解决循环依赖,避免多次从工厂创建实例 |
| 三级缓存 | singletonFactories | 创建 Bean 的工厂对象 (ObjectFactory<?>) | 用于延迟创建早期引用,是支持 AOP 代理的关键,确保返回正确的对象(原始或代理) |
其核心流程可以概括为:实例化 -> 提前暴露工厂 -> 依赖注入(若触发循环依赖则调用工厂)-> 完成初始化。下图以 ServiceA 和 ServiceB 相互依赖,且 ServiceA 需要 AOP 代理为例,展示了这一过程:
flowchart TD
A[开始创建 ServiceA] --> B[实例化 ServiceA<br>获取原始对象]
B --> C[将 ServiceA 的 ObjectFactory<br>存入三级缓存]
C --> D[为 ServiceA 进行属性填充<br>发现依赖 ServiceB]
D --> E[开始创建 ServiceB]
E --> F["实例化 ServiceB<br>获取原始对象"]
F --> G["将 ServiceB 的 ObjectFactory<br>存入三级缓存"]
G --> H["为 ServiceB 进行属性填充<br>发现依赖 ServiceA"]
H --> I["从三级缓存中获取<br>ServiceA 的 ObjectFactory"]
I --> J{"调用 ObjectFactory.getObject<br>判断 ServiceA 是否需要 AOP 代理?"}
J -- 是 --> K["生成 ServiceA 的<br>**代理对象**"]
J -- 否 --> L["返回 ServiceA 的<br>**原始对象**"]
K --> M[将代理对象存入二级缓存]
L --> M
M --> N[从三级缓存移除 ServiceA 的工厂]
N --> O["将获取到的早期引用<br>(代理对象)注入 ServiceB"]
O --> P["ServiceB 完成属性填充与初始化<br>成为完整 Bean, 存入一级缓存"]
P --> Q['ServiceA 注入已完成的 ServiceB<br>并继续完成其自身初始化']
Q --> R["ServiceA 初始化完成<br>(若需代理, 此处仍是代理对象 "]
R --> S["将完整的 ServiceA 存入一级缓存<br>并清理二、三级缓存中的 ServiceA"]
⚙️ 为何需要三级缓存?
你可能会问,为什么不能只用二级缓存(直接存放半成品对象)?
关键在于 AOP 代理创建的时机和唯一性。如果一个 Bean 需要被代理(例如使用了 @Transactional),那么最终暴露给其他 Bean 的必须是代理对象,而不是原始对象。
若没有三级缓存(ObjectFactory),只在二级缓存中存放原始对象:
- 注入错误对象:在循环依赖发生时,依赖方(如
ServiceB)将直接拿到ServiceA的原始对象并注入。即便后续ServiceA初始化完成后生成了代理对象,ServiceB持有的仍是原始对象的引用,导致 AOP 功能(如事务、日志)对其调用完全失效。 - 破坏单例原则:可能产生两个不同的对象:一个是二级缓存中的原始对象,另一个是初始化后生成的代理对象。这违背了单例模式的原则。
三级缓存通过存入一个 ObjectFactory 工厂来解决这个问题。这个工厂(其 getObject() 方法通常指向 getEarlyBeanReference() 方法)能够在被调用时,智能地判断是否需要返回代理对象,从而保证:
- 动态决策:仅在真正发生循环依赖、需要提前暴露引用时,才决定是返回原始对象还是创建代理对象。
- 保证唯一性:最终所有依赖方拿到的早期引用与最终存放在一级缓存中的成品 Bean 是同一个对象(无论是原始对象还是代理对象)。
- 性能优化:如果没有循环依赖,这个工厂就不会被调用,Bean 会按正常生命周期在初始化后生成代理,避免了不必要的提前代理创建。
⚠️ 注意事项与局限性
Spring 的这套机制虽然强大,但并非万能,理解其局限性很重要:
- 仅适用于单例 Bean:原型(Prototype)作用域的 Bean 无法使用三级缓存解决循环依赖,因为 Spring 不缓存原型 Bean 的实例。
- 不支持构造器循环依赖:如果循环依赖是通过构造器注入(Constructor Injection)方式发生的,三级缓存也无法解决。因为 Bean 在实例化(调用构造器)时就需要得到依赖项,而此时对象自身都还未创建,更无法提前暴露一个工厂或引用了。通常会抛出
BeanCurrentlyInCreationException。 - 避免在初始化方法中调用代理方法:Spring 官方建议,应避免在
@PostConstruct等初始化方法中,调用本类中需要被 AOP 拦截的方法。因为在初始化方法执行时,代理可能还未完全应用到当前 Bean 的自我引用上,导致调用绕过代理。
💎 总结
总而言之,Spring 的三级缓存与 AOP 的协作是一个精巧的设计:
- 三级缓存通过
ObjectFactory实现了早期引用的延迟创建,是支持 AOP 代理的关键。 - 它确保了在循环依赖场景中,依赖方注入的永远是最终正确的对象(可能是代理对象),保证了 AOP 功能的有效性。
- 这套机制是 Spring 在框架健壮性和功能完备性之间做出的一个务实而精彩的权衡。
希望这些解释能帮助你理解 Spring 三级缓存与 AOP 的协同原理。
🤔 参考 12
Spring 的三级缓存与 AOP 的协同工作机制是其解决循环依赖问题的核心设计,尤其在处理代理对象的一致性时至关重要。以下从 AOP 代理生成时机、三级缓存的动态适配 和 线程安全保障 三个维度详细解析:
一、AOP 代理的生成时机与三级缓存的适配
Spring 的 AOP 代理默认在 Bean 初始化完成后 生成(即 @PostConstruct 执行后),但在循环依赖场景下,这一流程会被打破。三级缓存通过以下方式协调两者的关系:
-
代理生成的提前触发
- 当 Bean A 被创建时,若其需要 AOP 代理(如标记了
@Transactional),Spring 会通过三级缓存的ObjectFactory提前生成代理对象,而非等待初始化完成。 - 示例流程:
// 创建 A 时,将工厂存入三级缓存 singletonFactories.put("A", () -> getEarlyBeanReference(A, beanDefinition, a)); // 生成代理对象(而非原始对象) Object earlyReference = factory.getObject();
- 当 Bean A 被创建时,若其需要 AOP 代理(如标记了
-
代理对象的动态注入
- 当 Bean B 依赖 A 时,从三级缓存获取 A 的工厂,生成代理对象并注入到 B 中。此时 B 持有的是 A 的代理引用,而非原始对象。
- 关键代码(简化):
// B 注入 A 时,从三级缓存获取代理 Object aProxy = singletonFactory.getObject(); b.setA(aProxy);
-
最终代理的统一性
- Bean A 完成初始化后,其最终形态(代理对象)会被放入一级缓存,后续所有依赖 A 的 Bean 均引用同一代理实例,确保 AOP 功能的一致性。
二、三级缓存如何解决 AOP 与循环依赖的冲突 1. 代理对象的延迟生成
- 无循环依赖时:AOP 代理在 Bean 初始化完成后生成,遵循默认生命周期。
- 存在循环依赖时:代理对象在 属性注入阶段 提前生成(通过
getEarlyBeanReference()),确保依赖注入的引用正确性。 - 设计意图:避免因代理生成延迟导致的引用不一致问题(如 B 持有原始 A,而 A 最终被代理)。
2. 工厂模式隔离代理逻辑
- 三级缓存存储的是
ObjectFactory,而非直接存储代理对象。 - 工厂的动态性:
- 若 Bean 需要代理,工厂返回代理对象;否则返回原始对象。
- 示例:
getEarlyBeanReference()方法会根据 Bean 是否被 AOP 增强决定返回值。
- 优势:解耦代理生成逻辑,避免硬编码判断。
3. AOP 代理的自我引用处理
- 当 Bean 的 AOP 代理需要引用自身时(如
@Async方法调用),Spring 通过Advised接口的getTargetSource()获取目标对象,确保代理链的正确性。 - 代码示例:
// 代理对象调用方法时,实际执行逻辑 public Object invoke(Object proxy, Method method, Object[] args) { // 通过目标对象执行方法(可能触发其他代理) return method.invoke(target, args); }
三、线程安全与潜在风险 1. 并发场景下的保障
- 缓存访问同步:通过
ConcurrentHashMap和双重检查锁(synchronized)保证多线程环境下缓存的原子性操作。 - 早期引用的唯一性:同一 Bean 的早期引用在三级缓存中仅生成一次,避免重复创建。
2. 代理对象的状态一致性
- 问题:代理对象在注入时可能尚未完成属性填充(如
@PostConstruct未执行)。 - 解决方案:
- 代理对象通过 目标对象引用 动态获取最新状态(如
((Advised) proxy).getTargetSource().getTarget())。 - 确保所有方法调用最终委托到完全初始化的目标对象。
- 代理对象通过 目标对象引用 动态获取最新状态(如
3. 构造器注入的局限性
- 构造器注入的循环依赖无法通过三级缓存解决,需改用 Setter 注入或
@Lazy延迟加载。 - 示例:
@Service public class A { private final B b; // 构造器注入导致循环依赖问题 public A(B b) { this.b = b; } }
四、设计总结与最佳实践 1. 核心设计目标
- 解耦依赖链:通过提前暴露半成品 Bean 打破循环等待。
- 兼容 AOP:动态生成代理对象,确保依赖注入的引用一致性。
- 性能优化:延迟代理生成,避免不必要的资源消耗。
2. 开发建议
- 优先使用 Setter/字段注入:规避构造器循环依赖。
- 合理使用
@Lazy:对非关键依赖延迟加载,减少初始化开销。 - 避免在
@PostConstruct中调用代理方法:确保代理已完全初始化。
3. 源码级验证
- 关键方法:
AbstractAutowireCapableBeanFactory#getEarlyBeanReference():生成早期引用(可能为代理)。AbstractAutoProxyCreator:负责创建 AOP 代理。
- 调试技巧:通过设置断点观察三级缓存的变化,验证代理生成时机。
五、总结 Spring 的三级缓存与 AOP 的协同设计体现了框架对 复杂场景的优雅解耦。通过工厂模式动态生成代理、分层缓存管理 Bean 生命周期,既解决了循环依赖问题,又确保了 AOP 功能的可靠性。开发者需深入理解这一机制,以规避潜在风险并优化应用性能。
🤔 参考 13
Spring 的三级缓存和 AOP(面向切面编程) 之间存在着紧密且巧妙的关系。可以说,三级缓存的设计,很大程度上是为了优雅地解决被 AOP 代理的 Bean 在发生循环依赖时产生的代理不一致问题。
下面我们深入剖析这两者如何协同工作。
核心结论先行
如果没有 AOP,理论上两级缓存(一级缓存存完整Bean,二级缓存存原始早期对象)就足以解决循环依赖。但引入 AOP 后,情况变得复杂,三级缓存成为了必需。三级缓存的核心使命之一是确保在循环依赖中,最终被注入的代理对象和最终放入容器的完整代理对象是同一个实例,从而保证单例原则。
1. 没有AOP的简单场景(为何两级缓存理论上可行)
假设只有 Bean A 和 Bean B 循环依赖,且它们都是普通 Bean,不需要被代理。
- 实例化 A(一个普通对象) -> 将 原始对象 A 放入二级缓存。
- A 填充属性时发现需要 B -> 去创建 B。
- 实例化 B(一个普通对象) -> 将 原始对象 B 放入二级缓存。
- B 填充属性时发现需要 A -> 从二级缓存中找到原始对象 A,注入给 B。
- B 初始化完成 -> 将完整对象 B 放入一级缓存,清除二级缓存中的 B。
- A 注入 B -> 初始化完成 -> 将完整对象 A 放入一级缓存,清除二级缓存中的 A。
在这个场景下,二级缓存存放的始终是原始的、未被增强的对象,注入和最终成品都是同一个对象,没有问题。
2. 引入AOP后的复杂场景(为何必须三级缓存)
现在假设 Bean A 需要被 AOP 代理(比如它身上有 @Transactional 注解)。问题来了:应该在什么时候为 A 创建代理对象?
有三个可能的时间点:
- 实例化后立刻创建(过早):如果 A 没有循环依赖,它根本不需要提前暴露,此时创建代理是浪费的。
- 初始化后创建(标准流程):这是 AOP 正常的代理时机。但如果 A 被循环依赖了,B 在填充属性时需要注入的是 A 的代理对象,而不是原始对象。如果等 A 完全初始化完再创建代理,B 就等不及了。
- 在被依赖时(即被其他Bean从缓存中获取时)创建(刚刚好):这正是三级缓存发挥作用的地方。
三级缓存与AOP的协作流程
让我们看下 Spring 如何用三级缓存解决这个难题。流程如下,关键步骤已加粗:
flowchart TD
A["开始创建Bean A"] --> B["1. 实例化A<br>(原始对象)"]
B --> C["2. 向三级缓存添加<br>ObjectFactory<br>(内含提前代理逻辑)"]
C --> D["3. 填充属性A<br>发现需要Bean B"]
D --> E["开始创建Bean B"]
E --> F["4. 实例化B<br>(原始对象)"]
F --> G["5. 向三级缓存添加<br>ObjectFactory"]
G --> H["6. 填充属性B<br>发现需要Bean A"]
H --> I["7. 从三级缓存获取A"]
I --> J["8. ObjectFactory.getObject<rb>执行<br>AbstractAutoProxyCreator.getEarlyBeanReference"]
J --> K["9. 提前生成<br>A的代理对象"]
K --> L["10. 将代理对象A<br>升级至二级缓存"]
L --> M["11. 代理对象A注入至B"]
M --> N["B完成创建<br>移至一级缓存"]
N --> O["12. A注入完整的B<br>继续初始化"]
O --> P["13. 初始化后处理<br>判断代理已存在则直接返回"]
P --> Q["14. A的代理对象<br>放入一级缓存"]
上图的核心在于第8、9步:ObjectFactory.getObject() 会调用 getEarlyBeanReference() 方法。这个方法存在于 AOP 相关的后置处理器(如 AbstractAutoProxyCreator)中。
- 如果 Bean 需要被代理,它就在这里提前生成并返回代理对象。
- 如果 Bean 不需要被代理,则直接返回原始对象。
这样做的好处是:
- 按需创建代理:只有在真正发生循环依赖、被其他 Bean 需要时,才会提前创建代理。如果没有循环依赖,则走正常的初始化后代理流程,性能更优。
- 保证单例:
getEarlyBeanReference()方法内部会维护一个记录早期代理的 Map,对于同一个 Bean,即使被多次索取,返回的都是同一个代理对象,严格防止了多个代理实例的产生。 - 职责分离:三级缓存(
ObjectFactory)作为一个“工厂”,将“创建早期引用”这个行为封装起来,使得创建逻辑(尤其是复杂的代理创建逻辑)与缓存管理逻辑解耦。
总结:三级缓存与AOP的关系
| 特性 | 解释 |
|---|---|
| 目的 | 解决被AOP代理的Bean在循环依赖中代理对象的统一性问题和按需创建问题。 |
| 关键角色 | 第三级缓存 (singletonFactories) 中存储的 ObjectFactory。 |
| 核心方法 | ObjectFactory.getObject() 最终会调用 AOP 组件的 getEarlyBeanReference() 方法来生成早期代理引用。 |
| 优势 | 1. 保证单例:确保在循环依赖中注入的和最终容器里的是同一个代理对象。 2. 延迟决策:只有在真正需要时(发生循环依赖)才提前创建代理,否则按正常生命周期进行。 |
简单来说,三级缓存是机制,AOP是场景。三级缓存提供了一个“钩子”(Hook),让 AOP 这种需要特殊创建逻辑的组件能够介入到 Bean 的早期曝光过程中,从而完美地解决了循环依赖带来的挑战。没有三级缓存,Spring 的 AOP 和依赖注入功能结合时将无法如此强大和稳定。
🤔 参考 14
Spring 的三级缓存机制与 AOP(面向切面编程) 深度协同工作,共同解决了循环依赖和 AOP 代理生成的矛盾。以下是两者关联的核心原理及关键细节:
一、为何需要结合?核心矛盾点
若存在循环依赖且其中一个 Bean 需要 AOP 代理(如 @Transactional),直接提前暴露未初始化的裸对象会导致以下问题:后续无法对其追加代理逻辑(因对象已固化)。
✅ 解决方案:通过三级缓存中的 ObjectFactory 延迟代理对象的生成时机,仅在首次被依赖时动态创建代理对象。
二、三级缓存 + AOP 的具体协作流程 1. 初始阶段:存入三级缓存
- 动作:创建 Bean 实例 → 包装成
ObjectFactory→ 存入singletonFactories(三级缓存)。 - 目的:暂不生成代理对象,保留生成能力给后续步骤[^3^][^5^]。
- 典型场景:Bean A 正在初始化,但其依赖的 Bean B 也依赖 A → 此时 A 以
ObjectFactory形式存入三级缓存。
2. 解决循环依赖:从三级缓存生成早期引用
- 触发条件:Bean B 尝试注入 Bean A,发现 A 尚未完成初始化。
- 关键操作:
- 从三级缓存取出 A 的
ObjectFactory→ 调用getObject()生成 A 的早期引用(非代理对象)。 - 将此早期引用升级到二级缓存
earlySingletonObjects,供 B 完成属性注入[^3^][^5^]。
- 从三级缓存取出 A 的
- 注意:此时仍是裸对象,尚未应用 AOP 逻辑。
3. 完成 AOP 代理:后置处理阶段
- 时机:当所有依赖关系解除后(即循环依赖打破),进入初始化收尾阶段。
- 动作:
- 检查当前 Bean 是否需要 AOP 代理(通过
InstantiationAwareBeanPostProcessor)。 - 如果需要代理 → 销毁早期裸对象 → 生成代理对象 → 存入一级缓存
singletonObjects。 - 如果不需要代理 → 直接将早期对象升级到一级缓存[^3^][^5^]。
- 检查当前 Bean 是否需要 AOP 代理(通过
- 优势:确保代理逻辑仅应用于最终完整的 Bean 实例,避免重复代理或逻辑错乱。
三、关键代码逻辑印证
// SingletonObjectFactory.getObject(): 这是三级缓存中ObjectFactory的实际调用方法
public Object getSingleton(String beanName, boolean allowEarlyReference) {
// ...省略校验逻辑...
if (factory instanceof SmartInstantiationAwareBeanPostProcessor) {
// 关键!尝试获取代理对象而非原始对象
return ((SmartInstantiationAwareBeanPostProcessor) factory).getEarlyBeanReference(beanName, id, this);
} else {
// 无AOP需求时直接返回原始对象
return factory.getObject();
}
}
- 说明:
SmartInstantiationAwareBeanPostProcessor(如 AOP 基础设施)在此介入,决定是否生成代理对象。若无此接口实现,则退回原始对象。
四、对比实验:有无 AOP 的差异
| 场景 | 无 AOP 代理 | 有 AOP 代理 |
|---|---|---|
| 三级缓存内容 | 普通 ObjectFactory | 支持代理的 SmartObjectFactory |
| 二级缓存对象 | 裸对象 | 裸对象 |
| 一级缓存结果 | 裸对象 | 代理对象 |
| 循环依赖处理 | 直接使用裸对象 | 通过工厂动态生成代理对象 |
五、设计意义
- 解耦初始化与代理:将对象实例化(解决循环依赖)与代理生成(AOP 逻辑)分离,避免相互阻塞。
- 按需代理:仅对确实需要代理的 Bean 生成代理对象,减少不必要的性能损耗。
- 线程安全:通过
synchronized块控制缓存升级过程,防止多线程下的竞态条件[^3^][^5^]。
总结
Spring 的三级缓存机制通过 singletonFactories 中的 ObjectFactory 实现了两大关键能力:
1️⃣ 破解循环依赖:提前暴露未完全初始化的对象引用;
2️⃣ 支持 AOP 代理:延迟到依赖关系解除后再生成代理对象。
二者的结合使得 Spring 既能处理复杂的循环依赖,又能无缝集成 AOP 功能,是 IoC 容器的核心设计之一。
🤔 参考 15
Spring 的三级缓存机制不仅用于解决循环依赖问题,还与 AOP(面向切面编程) 紧密相关,尤其是在创建代理对象的过程中。
🔗 三级缓存与 AOP 的关系
Spring 的三级缓存机制中,三级缓存(singletonFactories) 存储的是 ObjectFactory,它的作用是延迟创建代理对象,这为 AOP 的实现提供了支持。
🧠 为什么需要三级缓存来支持 AOP?
在使用 AOP(如 @Aspect、@Transactional)时,Spring 会为 Bean 创建代理对象(JDK 动态代理或 CGLIB 代理)。而如果这个 Bean 同时参与了循环依赖,那么在它还没有完成初始化时,就需要被其他 Bean 引用。
为保证 AOP 的代理逻辑依然有效,Spring 在三级缓存中通过 ObjectFactory 提前创建代理对象,而不是原始对象。
🔄 三级缓存 + AOP 的执行流程
以 Bean A 使用了 AOP 并与 Bean B 循环依赖为例:
-
创建 Bean A(原始对象)
- 调用构造函数,生成一个原始对象。
- 创建一个
ObjectFactory,用于生成 A 的代理对象,并放入三级缓存。
-
填充属性时发现 A 依赖 B
- 开始创建 Bean B。
-
B 需要引用 A
- 从三级缓存中通过
ObjectFactory获取 A 的代理对象。 - 将代理对象移动到二级缓存(earlySingletonObjects),并从三级缓存中移除工厂。
- 从三级缓存中通过
-
继续创建 B
- B 使用的是 A 的代理对象。
- B 完成初始化后放入一级缓存。
-
完成 A 的初始化
- A 继续注入 B,执行初始化方法。
- 最终将 A 的代理对象放入一级缓存。
✅ 总结
| 三级缓存层级 | 内容 | 与 AOP 的关系 |
|---|---|---|
| 一级缓存(singletonObjects) | 完全初始化好的 Bean(可能是代理对象) | 提供最终可用的 Bean,含 AOP 功能 |
| 二级缓存(earlySingletonObjects) | 提前暴露的早期 Bean(可能是代理对象) | 临时存放代理对象供其他 Bean 使用 |
| 三级缓存(singletonFactories) | ObjectFactory 工厂对象 | 按需创建代理对象,支持 AOP 与循环依赖共存 |
🚨 注意事项
- AOP 的代理对象只有在真正被需要时(如被其他 Bean 引用或发生循环依赖)才会被创建。
- 如果没有三级缓存机制,AOP 和循环依赖将无法同时支持。
🧩 结论
Spring 的三级缓存机制不仅解决了单例 Bean 的循环依赖问题,还通过 ObjectFactory 实现了代理对象的延迟创建,从而完美支持 AOP 的运行。这是 Spring 容器设计中一个非常巧妙和关键的机制。