***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| customAuthenticationFilter defined in file [/Users/hwang-in-woo/projects/NBE3-4-2-Team10/backend/out/production/classes/com/ll/TeamProject/global/security/CustomAuthenticationFilter.class]
↑ ↓
| userService defined in file [/Users/hwang-in-woo/projects/NBE3-4-2-Team10/backend/out/production/classes/com/ll/TeamProject/domain/user/service/UserService.class]
↑ ↓
| securityConfig defined in file [/Users/hwang-in-woo/projects/NBE3-4-2-Team10/backend/out/production/classes/com/ll/TeamProject/global/security/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 1
작업 과정에서 위와 같은 순환 참조 오류가 발생하는 경우가 있었다.
user.changePassword(passwordEncoder.encode(password));
userService에서 비밀번호 변경 과정 중 비밀번호 암호화를 진행할 때 발생하는데
코드 상으로는 순환 의존성이 없을 것 같음에도 오류가 발생하고 있다.
.addFilterBefore(customAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
가장 먼저, 스프링 시큐리티의 필터로 CustomAuthenticationFilter를 등록하는 과정에서
당연히 customAuthenticationFilter에 대한 의존성이 추가된다.
SiteUser user = userService.getUserFromAccessToken(accessToken);
...
Optional<SiteUser> opUser = userService.findByApiKey(apiKey);
...
String newAccessToken = userService.genAccessToken(user);
그리고 customAuthenticationFilter 내부에서 인증 과정에서
엑세스 토큰을 기반으로 사용자를 조회하거나,
API 키를 통해 사용자를 찾고 새로운 엑세스 토큰으로 갱신하는 과정에서
UserService 에서 정의된 메서드들을 사용하게 되며 해당 의존성이 추가된다.
user.changePassword(passwordEncoder.encode(password));
마지막으로 비밀번호 변경을 위해 passwordEncoder를 가져오게 되는데
현재 passwordEncoder는 securityConfig 안에서 bean으로 등록되어 있다.
@Bean
@Lazy
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
바로 여기가 문제인 부분이다.
securityConfig와 비밀번호 암호화는 직접적인 관련이 없는데 같이 묶여있기 때문에
비밀번호 암호화를 사용하려면 securityConfig의 모든 부분이 의존성으로 엮이게 되는 것이다.
이에 대한 해결은 간단하다.
securityConfig의 필터체인 부분이나 CORS 와 비밀번호 암호화는 사용하는 상황이 다르기 때문에
PasswordEncoder를 독립적인 클래스 파일로 분리하면 된다.
아래와 같이 PasswordEncoderConfig.java 로 분리하였다.
@Configuration
public class PasswordEncoderConfig {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
순환 오류 문제가 해결된다.