1. 개요
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| principalOauth2UserService (field private org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder com.cos.security1.config.outh.PrincipalOauth2UserService.bCryptPasswordEncoder)
↑ ↓
| securityConfig defined in file [E:\\Project\\SpringWebStudy\\security1\\out\\production\\classes\\com\\cos\\security1\\config\\SecurityConfig.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Process finished with exit code 0
간단한 security 기능을 구현해보다가 순환참조 문제를 겪었다. Spring Boot 2.6.x 이후 버전은 순환 참조를 기본값으로 금지하고 있어서 애플리케이션 실행시 위와 같은 에러가 발생했다.
이번 기회에 순환참조 문제에 대해서 제대로 이해하고 해결 방법에 대해 정리해보자.
참고로 Spring Boot 3.1.3 버전을 사용 중이다.
2. 문제 코드
SecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig {
private final PrincipalOauth2UserService principalOauth2UserService;
@Bean
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
...
}
PrincipalOauth2UserService.java
@Service
@RequiredArgsConstructor
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final UserRepository userRepository;
...
}
순환참조가 발생한 이유는 SecurityConfig를 스프링 빈으로 등록하고 의존관계를 주입할 때, PrincipalOauth2UserService 빈을 주입받게 된다. 그리고 PrincipalOauth2UserService 를 스프링 빈으로 등록하고 의존관계를 주입할 때BCryptPasswordEncoder 빈을 주입받게 된다. 하지만 BCryptPasswordEncoder빈은 SecurityConfig에서 관리하는 빈이다. 그로인해 SecurityConfig와 PrincipalOauth2UserService 는 서로를 순환하면서 참조하게 된다. 스프링 부트는 이걸 런타임시 에러를 발생시킨다.
3. 문제해결
@Lazy 등 간단하게 어노테이션으로 해결할 수 있지만, 문제를 근본적으로 해결하기 위해서는 서로를 참조하지 않도록 재설계 하면 된다.
BCryptPasswordEncoder를 다른 파일에서 설정해주면 된다.
SecurityConfig.java 에 있던 BCryptPasswordEncoder를 빈으로 등록하는 코드를 다른 설정파일(AppConfig.java)로 옮겨주자.
@Configuration
public class AppConfig {
@Bean
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
}
'Programming > Spring' 카테고리의 다른 글
[Spring] 스프링 컨테이너가 빈을 등록하는 방법 (1) | 2024.01.10 |
---|---|
[Spring] @Autowired에서 조회 빈이 2개 이상인 경우 (1) | 2024.01.10 |
[Spring Boot] Spring Boot + ES 예제 (0) | 2023.09.28 |
[Spring Boot] Spring Boot + Kafka 예제 (0) | 2023.09.26 |
[Spring Boot] Spring Data JPA + PostgreSQL 예제 (0) | 2023.09.25 |