1. 순환 의존성이란 무엇입니까?
2. Spring에 일어나는 일
BeanCurrentlyInCreationException
을 발생시킵니다 .생성자 주입
을 사용할 때 Spring에서 발생할 수 있습니다 . 다른 유형의 주입을 사용하는 경우 컨텍스트 로딩이 아닌 필요할 때 의존성이 주입되므로 이 문제가 발생하지 않아야 합니다.3. 간단한 예
@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(CircularDependencyB circB) {
this.circB = circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
@Autowired
public CircularDependencyB(CircularDependencyA circA) {
this.circA = circA;
}
}
이제 구성 요소를 스캔할 기본 패키지를 지정하는 테스트용 Configuration 클래스(
TestConfig 라고 함)를 작성할 수 있습니다.
빈이 " 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 'circularDependencyA':
Requested bean is currently in creation: Is there an unresolvable circular reference?
4. 해결 방법
4.1. 재설계
4.2. @Lazy 사용
CircularDependencyA
를 변경할 수 있습니다 .@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public CircularDependencyA(@Lazy CircularDependencyB circB) {
this.circB = circB;
}
}
지금 테스트를 실행하면 이번에는 오류가 발생하지 않음을 알 수 있습니다.
4.3. 세터/필드 주입 사용
message
)를 추가해 보겠습니다.@Component
public class CircularDependencyA {
private CircularDependencyB circB;
@Autowired
public void setCircB(CircularDependencyB circB) {
this.circB = circB;
}
public CircularDependencyB getCircB() {
return circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
private String message = "Hi!";
@Autowired
public void setCircA(CircularDependencyA circA) {
this.circA = circA;
}
public String getMessage() {
return message;
}
}
이제 단위 테스트를 약간 변경해야 합니다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class CircularDependencyTest {
@Autowired
ApplicationContext context;
@Bean
public CircularDependencyA getCircularDependencyA() {
return new CircularDependencyA();
}
@Bean
public CircularDependencyB getCircularDependencyB() {
return new CircularDependencyB();
}
@Test
public void givenCircularDependency_whenSetterInjection_thenItWorks() {
CircularDependencyA circA = context.getBean(CircularDependencyA.class);
Assert.assertEquals("Hi!", circA.getCircB().getMessage());
}
}
이러한 어노테이션을 자세히 살펴보겠습니다.
@Bean
은 주입할 빈의 구현을 검색하는 데 이러한 메서드를 사용해야 한다고 Spring 프레임워크에 알려줍니다.그리고@Test
어노테이션을 사용하여 테스트는 컨텍스트에서CircularDependencyA 빈을 가져오고
CircularDependencyB
가 적절하게 주입되었는지 확인하여메시지
속성 값을 확인합니다.4.4. @PostConstruct 사용
@Autowired 를 사용하여 의존성을 주입한 다음
@PostConstruct
로 어노테이션이 달린 메서드를 사용하여 다른 의존성을 설정하는 것입니다.우리의 빈은 다음과 같은 코드를 가질 수 있습니다:@Component
public class CircularDependencyA {
@Autowired
private CircularDependencyB circB;
@PostConstruct
public void init() {
circB.setCircA(this);
}
public CircularDependencyB getCircB() {
return circB;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
private String message = "Hi!";
public void setCircA(CircularDependencyA circA) {
this.circA = circA;
}
public String getMessage() {
return message;
}
}
그리고 이전에 했던 것과 동일한 테스트를 실행할 수 있으므로 순환 의존성 예외가 여전히 발생하지 않고 의존성이 올바르게 주입되었는지 확인합니다.
4.5. ApplicationContextAware 및 InitializingBean 구현
빈 중 하나가 ApplicationContextAware
를 구현 하면 빈은 Spring 컨텍스트에 액세스할 수 있으며 다른 빈을 추출할 수 있습니다.InitializingBean
을 구현함으로써 우리는 이 빈이 모든 속성이 설정된 후에 몇 가지 작업을 수행해야 함을 나타냅니다. 이 경우 의존성을 수동으로 설정하려고 합니다.다음은 빈에 대한 코드입니다.@Component
public class CircularDependencyA implements ApplicationContextAware, InitializingBean {
private CircularDependencyB circB;
private ApplicationContext context;
public CircularDependencyB getCircB() {
return circB;
}
@Override
public void afterPropertiesSet() throws Exception {
circB = context.getBean(CircularDependencyB.class);
}
@Override
public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
context = ctx;
}
}
@Component
public class CircularDependencyB {
private CircularDependencyA circA;
private String message = "Hi!";
@Autowired
public void setCircA(CircularDependencyA circA) {
this.circA = circA;
}
public String getMessage() {
return message;
}
}
다시, 이전 테스트를 실행하고 예외가 발생하지 않았으며 테스트가 예상대로 작동하는지 확인할 수 있습니다.