手把手教你解决循环依赖的方法
第一,循环依赖是什么?
类A依赖类B,类B也依赖类A,这种情况会导致循环依赖。
BeanA→BeanB→BeanA
以上是比较容易发现的循环依赖,也有更深层次的循环依赖。
BeanA→BeanB→BeanC→BeanD→BeanE→BeanA
Spring的循环依赖于
当Spring上下文加载所有bean时,它会尝试按照它们之间关系的顺序来创建。如果没有循环依赖,例如:
BeanA→BeanB→BeanC
首先,Spring将创建BeanC,然后创建BeanB(并将BeanC注入BeanB),最后创建BeanA(并将BeanB注入BeanA)。
但如果我们有循环依赖,Spring上下文不知道应该先创建哪一个Bean,因为它们是相互依赖的。在这种情况下,Spring会在加载上下文时抛出一个BeanCurrentlyInCreationException。
如果我们使用结构方法进行注入,就会遇到这样的情况。由于这是上下文加载,所以需要注入。
举个栗子
在组织类中,用户类需要调用方法,因此通过构造方法注入组织类。
@Service
public class UserService {
private final DepartmentService departmentSerivce;
/**
* 通过构造方法注入DepartmentService类
*/
@Autowired
public UserSerivce(DepartmentService departmentService) {
this.departmentService = departmentService;
}
public List<Department> list() {
retern departmentService.list();
}
}
而组织类也刚好需要调用用户类里的方法,于是它也通过构造方法注入用户类。
@Service
public class DepartmentService {
private final UserService userSerivce;
/**
* 通过构造方法注入UserService类
*/
@Autowired
public DepartmentSerivce(UserService userSerivce) {
this.userSerivce = userSerivce;
}
}
这种情况程序在编译时,就会报下面的错误
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| userService defined in file [D:\Java\IdeaProjects\UserService.class]
↑ ↓
| departmentService defined in file [D:\Java\IdeaProjects\DepartmentService.class]
└─────┘
现在我们可以为测试编写一个配置类,让我们称之为TestConfig,它指定要扫描组件的基本包。让我们假设我们的bean在包"com.baeldung.circulardependency"中定义:
@Configuration
@ComponentScan(basePackages = { "com.baeldung.circulardependency" })
public class TestConfig {
}
最后,我们可以编写一个 JUnit 测试来检查循环依赖关系。测试可以为空,因为在上下文加载期间将检测到循环依赖关系。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class CircularDependencyTest {
@Test
public void givenCircularDependency_whenConstructorInjection_thenItFails() {
// Empty test; we just want the context to load
}
}
如果您尝试运行此测试,您将得到以下异常:
BeanCurrentlyInCreationException: Error creating bean with name 'UserService':
Requested bean is currently in creation: Is there an unresolvable circular reference?