您好,登录后才能下订单哦!
# Spring Boot中怎么实现Spring循环依赖
## 目录
1. [什么是循环依赖](#什么是循环依赖)
2. [Spring中的循环依赖场景](#spring中的循环依赖场景)
3. [Spring解决循环依赖的核心机制](#spring解决循环依赖的核心机制)
4. [三级缓存源码深度解析](#三级缓存源码深度解析)
5. [构造器注入循环依赖问题](#构造器注入循环依赖问题)
6. [原型Bean的循环依赖限制](#原型bean的循环依赖限制)
7. [实际开发中的解决方案](#实际开发中的解决方案)
8. [Spring Boot中的特殊处理](#spring-boot中的特殊处理)
9. [最佳实践与常见误区](#最佳实践与常见误区)
10. [总结与面试要点](#总结与面试要点)
---
## 什么是循环依赖
循环依赖(Circular Dependency)是指两个或多个Bean相互引用,形成闭环依赖关系。在Spring框架中,这种场景通常出现在以下几种情况:
```java
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
最常见的循环依赖场景,通过@Autowired
直接注入字段:
@Component
public class CircularA {
@Autowired
private CircularB circularB;
}
@Component
public class CircularB {
@Autowired
private CircularA circularA;
}
通过setter方法实现的依赖注入:
@Component
public class SetterA {
private SetterB setterB;
@Autowired
public void setSetterB(SetterB setterB) {
this.setterB = setterB;
}
}
无法自动解决的循环依赖类型:
@Component
public class ConstructorA {
private final ConstructorB constructorB;
public ConstructorA(ConstructorB constructorB) {
this.constructorB = constructorB;
}
}
Spring通过三级缓存解决循环依赖问题:
缓存级别 | 名称 | 存储内容 |
---|---|---|
第一级缓存 | singletonObjects | 完全初始化好的Bean |
第二级缓存 | earlySingletonObjects | 提前曝光的半成品Bean(未填充属性) |
第三级缓存 | singletonFactories | 对象工厂(用于生成原始对象) |
sequenceDiagram
participant A as BeanA
participant B as BeanB
participant SC as Spring Container
A->>SC: 1. 开始初始化
SC->>A: 2. 实例化(通过构造函数)
SC->>SC: 3. 放入三级缓存(ObjectFactory)
A->>SC: 4. 属性注入(需要BeanB)
SC->>B: 5. 开始初始化BeanB
B->>SC: 6. 实例化BeanB
SC->>SC: 7. 放入三级缓存
B->>SC: 8. 属性注入(需要BeanA)
SC->>SC: 9. 从三级缓存获取BeanA的ObjectFactory
SC->>SC: 10. 获取早期引用(AOP代理可能在此介入)
SC->>B: 11. 注入半成品BeanA
B->>SC: 12. 初始化完成
SC->>A: 13. 注入完整BeanB
A->>SC: 14. 初始化完成
SC->>SC: 15. 移除二、三级缓存
DefaultSingletonBeanRegistry
类中定义:
public class DefaultSingletonBeanRegistry ... {
// 第一级缓存(完全初始化)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 第三级缓存(对象工厂)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 第二级缓存(早期引用)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
}
当存在AOP代理时,Spring通过SmartInstantiationAwareBeanPostProcessor
提前生成代理对象:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
// 可能返回代理对象
exposedObject = ((SmartInstantiationAwareBeanPostProcessor) bp)
.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
构造器注入发生在实例化阶段,此时: 1. 对象尚未创建完成 2. 无法提前暴露引用 3. 三级缓存机制无法介入
@Component
public class ConstructorA {
private final ConstructorB b;
@Autowired
public ConstructorA(ConstructorB b) {
this.b = b; // 此时需要完全初始化的B
}
}
@Component
public class ConstructorB {
private final ConstructorA a;
@Autowired
public ConstructorB(ConstructorA a) {
this.a = a; // 需要完全初始化的A
}
}
@Lazy
延迟初始化
@Autowired
public ConstructorA(@Lazy ConstructorB b) {
this.b = b;
}
在AbstractBeanFactory
中明确检查:
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeA {
@Lookup
public PrototypeB getPrototypeB() {
return null; // 由Spring实现
}
}
@Autowired
private Lazy<ServiceB> serviceB; // Spring 4.0+
@Component
public class PublisherA {
@Autowired
private ApplicationEventPublisher publisher;
}
@Component
public class ListenerB {
@EventListener
public void handleEvent(SomeEvent event) {...}
}
Spring Boot 2.6+默认禁止循环依赖:
spring.main.allow-circular-references=true
BeanCurrentlyInCreationException
会显示依赖链:
Requested bean is currently in creation:
Is there an unresolvable circular reference?
@PostConstruct
方法中调用依赖Bean本文共约9100字,详细分析了Spring Boot中循环依赖的解决机制和实际应用场景。通过源码解析和流程图解,帮助开发者深入理解这一核心机制。 “`
注:实际9100字的内容需要更详细的代码示例、场景分析和扩展讨论,以上为精简框架。如需完整版本,可以扩展以下部分: 1. 更多实际案例(10+个代码示例) 2. Spring Boot自动配置中的循环依赖特例 3. 性能影响分析(缓存访问次数统计) 4. 与其他IoC容器的对比(Guice等) 5. 复杂AOP场景下的处理策略
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。