TIL_0215 - 순환 의존성 문제

johaS2·2025년 2월 15일

Spring에서 순환 의존성 문제 해결하기

프로젝트에서 순환 의존성 에러가 발생했고 해결하는 과정에서 시행착오를 겪었다.

이 오류는 Spring의 의존성 주입에서 발생한 순환 참조 문제로, 두 개 이상의 빈이 서로를 참조해 무한 루프를 일으키는 상황이다.

문제 원인

처음에는WebSecurityConfigUserDetailsServiceImpl 간의 순환 의존성 문제라고 생각했다. WebSecurityConfigJwtUtilUserDetailsServiceImpl을 의존하고, UserDetailsServiceImplWebSecurityConfig를 간접적으로 의존하는 구조여서 순환 의존성 문제가 발생한다고 생각했다.

하지만PasswordEncoder 빈을 주입하는 과정에서 발생한 간접적인 순환 의존성이 문제의 주요 원인이었다. WebSecurityConfigPasswordEncoder를 의존하고 있었고, 이로 인해 PasswordEncoder 빈이 다시 WebSecurityConfig를 간접적으로 의존하게 되어 순환 의존성이 발생한 것이다.

여기에 생성자 주입 방식을 사용하고 있어서 Spring이 의존성 주입을 해결할 수 없어 에러가 발생했다.

해결 시도

  1. @Lazy 어노테이션 사용
    @Lazy를 사용하면 의존성 주입을 지연시켜 순환 참조를 방지할 수 있다고 했다. 하지만 간접적인 의존성까지 해결되진 않았다.
@Autowired
public WebSecurityConfig(JwtUtil jwtUtil, @Lazy UserDetailsServiceImpl userDetailsService, AuthenticationConfiguration authenticationConfiguration) {
    this.jwtUtil = jwtUtil;
    this.userDetailsService = userDetailsService;
}
  1. PasswordConfig 클래스를 분리
    WebSecurityConfig에서 PasswordEncoder 빈을 의존하고 있었기 때문에 별도의 클래스로 분리하여 해결했다.
@Configuration
public class PasswordConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

마무리

간접적인 의존성도 순환 의존성 문제를 일으킬 수 있다는 점을 알게 되었다. @Lazy 어노테이션으로 해결되지 않았던 이유도 이 때문이었다. 결국 구성 요소를 분리하는 것이 순환 의존성 문제를 해결하는 효과적인 방법임을 깨달았다.
Spring의 의존성 관리에 대해 더 깊이 이해할 필요성을 느꼈고, 앞으로는 순환 의존성 문제를 미리 예방할 방법을 더 고민해야겠다!

profile
passionate !!

0개의 댓글