들어가며
스프링에서 프로젝트를 진행하면 종종 빈 순환 참조
가 발생하는데, 이에 대한 해결책을 알아보자.
들어가기에 앞서, 빈 순환 참조는 생성자를 통해서 빈을 주입했을 때, Bean A -> Bean B -> Bean A … 계속해서 순환 참조하는 것을 말한다.
1. 빈 순환 참조가 발생하는 상황
@Component
public class CircularA {
private CircularB circularB;
public CircularA(CircularB circularB) {
this.circularB = circularB;
}
}
@Component
public class CircularB {
private CircularA circularA;
public CircularB(CircularA circularA) {
this.circularA = circularA;
}
}
각각 @Component를 통해서 빈으로 등록시킨다. 상대방 빈을 생성자를 통해서 주입받는다. CircularA 컴포넌트는 빈으로 등록될 때CircularB를 참조하고 있고, CircularB 컴포넌트도 빈으로 등록할 때 Circular A를 참조한다.
@SpringBootTest
@RunWith(SpringRunner.class)
public class CircularTest {
@Test
public void test() {
// just spring context load
}
}
애플리케이션을 띄우거나, 아무것도 작성되지 않은 테스트 케이스를 돌리게되면 다음과 같은 예외가 발생한다.
**************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| circularA defined in file [/Users/andrew/workspace/spring-boot-practice/target/classes/com/example/demo/spring/circular/CircularA.class]
↑ ↓
| circularB defined in file [/Users/andrew/workspace/spring-boot-practice/target/classes/com/example/demo/spring/circular/CircularB.class]
└─────┘
순환참조가 발생했고, 어떤 빈에서 순환 참조가 일어나는지 알려준다.
2. 해결 방법 1. @Lazy
여러 가지 해결 방법이 있지만, 기본적인 원리는 서로 빈이 생성되는 시기를 늦추거나 조율해서 동시에 참조하는게 아니라, 하나의 빈이 생성이 완료 된 후, 동작을 하게끔 만들어 주는게 키포인트!
@Component
public class CircularA {
private CircularB circularB;
public CircularA(@Lazy CircularB circularB) {
this.circularB = circularB;
}
}
사실 여러 개의 블로그를 봤지만, 결국 빈 순환 참조가 난다는 것은 모델링 설계가 잘못되었음을 알려주는 것이라고 했다. 그렇기 때문에 위에 방법들은 궁극적인 해결책 보다는 가벼운 임시 조치! 아니면 @Autowired, @Inject 어노테이션을 사용하는 것 뿐
📚 Related Posts
- Spring WebFlux 테스트 방법
- Spring과 MongoDB 연동 실전 가이드
- SpringBoot, MongoDB 시작하기
- Spring Boot 서버 타임존 설정 방법
- SpringBoot CommandLineRunner, ApplicationRunner 초기화 방법
- Jackson, LocalDateTime Serialization, Deserialization 이슈
- Spring Boot, Dockerfile로 이미지 생성, 배포하기
- SpringBoot RabbitMQ 연동하기
- Junit5 정리
- Spring Sentry(에러 트래킹 서비스) 적용하기
- [Spring] 빈 주입하는 방법 && Best Practice
- Thymeleaf 실무에서 자주 사용하는 것들
- Thymeleaf Collection 정보 화면에 렌더링하기
- Spring, JPA를 이용한 REST API 만들기
- [Spring] MultipartFile을 이용한 파일 업로드
- [Spring] 모델 검증(validation)
- [Spring]HandlerMethodArgumentResolver 인터페이스
- [Spring] DispatcherServlet에 대해서 알아보자
- [Spring] MVC 만들어 보기
- [Spring] 메세지 컨버터
- [Spring] MVC 살펴보기
- [Spring] @ConfigurationProperties를 이용해서 properties값들을 클래스로 관리하기
- [Spring] Profile 설정하기
- [Spring] SpringApplication를 통한 코딩
- [Spring Boot] 스프링 부트 3가지 특징
- [Spring] @SpringBootAppllication 어노테이션에 대한 고찰
- [Spring] bean circular dependencies (빈 순환 참조)
- [Spring]Bean에 대해서 알아보자
- SpringBoot, JPA, H2를 이용한 간단한API 작성
- [Spring] Spring Data Common 프로젝트 살펴보기