#SpringBoot核心 #依赖注入 #设计模式 #性能优化
循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系。
典型场景:
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
Spring启动时抛出异常:
BeanCurrentlyInCreationException: Error creating bean with name 'serviceA':
Requested bean is currently in creation: Is there an unresolvable circular reference?
Spring通过三级缓存解决Setter/Field注入的循环依赖,但无法解决构造器注入的循环依赖。
缓存级别 | 存储内容 |
---|---|
一级缓存(singletonObjects) | 完全初始化的Bean |
二级缓存(earlySingletonObjects) | 提前暴露的早期Bean(未完成属性填充) |
三级缓存(singletonFactories) | Bean工厂对象(用于生成早期引用) |
1. 创建ServiceA → 将原始对象工厂放入三级缓存
2. 填充ServiceA属性 → 发现需要ServiceB
3. 创建ServiceB → 将原始对象工厂放入三级缓存
4. 填充ServiceB属性 → 从三级缓存获取ServiceA的工厂 → 生成代理对象
5. ServiceB初始化完成 → 移入一级缓存
6. ServiceA继续填充ServiceB → 从一级缓存获取ServiceB → 完成初始化
构造器注入循环依赖无法解决(Spring 5.3+默认禁止):
// 错误示例:启动直接失败
@Service
public class ServiceA {
private final ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
强制允许构造器循环依赖(不推荐):
# application.properties
spring.main.allow-circular-references=true
将构造器注入改为Setter注入:
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private ServiceA serviceA;
@Autowired
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
强制延迟其中一个Bean的初始化:
@Service
public class ServiceA {
@Lazy
@Autowired
private ServiceB serviceB;
}
原理:ServiceB被代理,首次调用时才会真实初始化。
通过接口隔离实现类依赖:
public interface IServiceA {
void doSomething();
}
public interface IServiceB {
void doAnother();
}
@Service
public class ServiceAImpl implements IServiceA {
@Autowired
private IServiceB serviceB;
}
@Service
public class ServiceBImpl implements IServiceB {
@Autowired
private IServiceA serviceA;
}
高层模块不应依赖低层模块,二者都应依赖抽象:
// 定义数据访问接口
public interface UserRepository {
User findById(Long id);
}
// 高层服务依赖接口
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}
// 低层实现
@Repository
public class JpaUserRepository implements UserRepository {
// 实现细节
}
通过ApplicationEvent解耦强依赖:
// ServiceA发布事件
@Service
public class ServiceA {
@Autowired
private ApplicationEventPublisher publisher;
public void triggerEvent() {
publisher.publishEvent(new CustomEvent(this));
}
}
// ServiceB监听事件
@Service
public class ServiceB {
@EventListener
public void handleEvent(CustomEvent event) {
// 处理逻辑
}
}
Spring Assistant
插件)STS (Spring Tool Suite)
插件提示<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
运行命令:
mvn spring-boot:run -Dspring-boot.run.profiles=dev
user-service
, order-service
)common
模块黄金法则:
紧急修复流程:
发现循环依赖 → 使用@Lazy临时解决 → 标记为技术债务 → 排期重构
工具推荐:
通过合理设计+规范约束,可有效避免循环依赖,构建高可维护的Spring Boot应用!