Spring Boot 프로젝트에서 OAuth2 로그인 구현 중, 어플리케이션이 실행되지 않고 순환 참조 문제가 발생했다.
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| webConfig defined in file [/path/to/project/WebConfig.class]
↑ ↓
| OAuth2AuthenticationSuccessHandler defined in file [/path/to/project/OAuth2AuthenticationSuccessHandler.class]
↑ ↓
| OAuth2UserUnlinkManager defined in file [/path/to/project/OAuth2UserUnlinkManager.class]
↑ ↓
| googleOAuth2UserUnlink defined in file [/path/to/project/GoogleOAuth2UserUnlink.class]
└─────┘
Spring Boot 2.6 이상에서는 순환 참조가 기본적으로 금지되어 있어 어플리케이션이 시작되지 않았다.
콘솔 화면을 확인해보면 친절하게도 어떻게 순환 참조가 발생하고 있는지 확인 할 수 있다.
각 클래스가 서로의 빈(Bean)을 주입받는 과정에서 순환 참조가 발생했다.
WebConfig 에서 RestTemplate를 생성자로 주입하고 있고,
OAuth2UserUnlink각각의 OAuth2UserUnlink 클래스에서 동일한 방식으로 주입.
@Component
public class RestTemplateFactory {
private final RestTemplateBuilder restTemplateBuilder;
public RestTemplateFactory(RestTemplateBuilder restTemplateBuilder) {
this.restTemplateBuilder = restTemplateBuilder;
}
public RestTemplate create() {
return restTemplateBuilder.build();
}
}
이후 필요한 곳에서 RestTemplate를 직접 생성하는 대신 RestTemplateFactory의 create() 메서드를 호출하도록 수정
@Service
public class SomeService {
private final RestTemplate restTemplate;
public SomeService(RestTemplateFactory restTemplateFactory) {
this.restTemplate = restTemplateFactory.create();
}
}
@Service
public class OAuth2AuthenticationSuccessHandler {
private final OAuth2UserUnlinkManager unlinkManager;
public OAuth2AuthenticationSuccessHandler(@Lazy OAuth2UserUnlinkManager unlinkManager) {
this.unlinkManager = unlinkManager;
}
}
spring.main.allow-circular-references=true
RestTemplateFactory를 도입함으로써 RestTemplateBuilder의 반복 사용을 제거하고, 순환 참조 문제를 해결할 수 있었다.
의존성 설계의 중요성과 해결 방안에 대한 좋은 학습 기회가 되었다.
와 진짜 이건 노벨상 감입니다.