Notice
Recent Posts
Recent Comments
Link
반응형
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 강화학습
- 딕셔너리
- 딥러닝
- 이진탐색
- 머신러닝
- 파이썬 오류
- 코테
- 프로그래머스
- 캐싱
- 깊이우선탐색
- BOJ
- 비지도학습
- 멱등
- rest api
- post
- 파이썬
- bineary search
- 자바
- 백준
- 스택과 힙
- Merge sort
- 해시
- 오버라이딩
- 코딩테스트
- HTTP
- 파이썬 알고리즘
- 알고리즘
- 코딩
- 지도학습
- 너비우선탐색
Archives
- Today
- Total
chae._.chae
[Error] 순환참조 오류 - The dependencies of some of the beans in the application context form a cycle 본문
Error
[Error] 순환참조 오류 - The dependencies of some of the beans in the application context form a cycle
walbe0528 2022. 11. 11. 23:15728x90
반응형

application context에서 일부 Bean의 순환 참조 문제가 발생했다.
순환 참조 문제는 둘 이상의 Bean이 생성자를 통해 서로 주입하려고 할 때 발생한다.
즉, 클래스 A에서 생성자 주입을 통해 클래스 B의 인스턴스가 필요하고,
클래스 B는 생성자 주입을 통해 클래스 A의 인스턴스가 필요한 상황인 것이다.
@Component
public class AComponent {
@Autowired
private BComponent bComponent;
}
@Component
public class BComponent {
@Autowired
private AComponent aComponent;
}
이런 상황이다.
내가 작성한 코드인데, SecurityConfig와 PrincipalOauth2UserService에서 서로 주입하려 해서 문제가 발생했다.
- SecurityConfig.class
@AllArgsConstructor
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private PrincipalOauth2UserService principalOauth2UserService;
@Bean // 해당 메소드의 리턴되는 오브젝트를 IoC로 등록해준다.
public BCryptPasswordEncoder encodePwd(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/user/**").authenticated()
.antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/loginForm")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/")
.and()
.oauth2Login()
.loginPage("/loginForm")
.userInfoEndpoint()
.userService(principalOauth2UserService); // 소셜 로그인 후처리작업 진행
}
}
- PrincipalOauth2UserService.class
@Service // 로그인 완료후 진행되는 후처리 작업
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private UserRepository userRepository;
// loadUser : 구글로부터 받은 userRequest 데이터에 대한 후처리되는 함수
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
System.out.println("userRequest: " + userRequest); // userRequest: org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest@703cff7b
System.out.println("userRequest.getClientRegistration(): " + userRequest.getClientRegistration()); // registrationId로 어떤 OAuth로 로그인했는지 확인 가능
System.out.println("userRequest: " + userRequest.getAccessToken().getTokenValue());
OAuth2User oauth2User = super.loadUser(userRequest);
// 구글로그인 완료시 code를 리턴받는다. -> (OAuth-Client라이브러리가 받아준다) -> 코드를 통해 Access Token 요청
// userRequest 정보로 회원프로필을 받는다.(이때 사용하는 함수가 loadUser)
// 강제로 회원가입을 진행
String provider = userRequest.getClientRegistration().getRegistrationId(); // "google"
String providerId = oauth2User.getAttribute("sub"); // 구글의 sub
String username = provider + "_" + providerId;
String password = bCryptPasswordEncoder.encode("시큐리티");
String email = oauth2User.getAttribute("email");
String role = "ROLE_USER";
User userEntity = userRepository.findByUsername(username);
if (userEntity == null){ // 유저 찾지 X, 강제로 회원가입 진행
userEntity = User.builder()
.username(username)
.password(password)
.email(email)
.role(role)
.provider(provider)
.providerId(providerId)
.build();
userRepository.save(userEntity);
}
return new PrincipalDetails(userEntity, oauth2User.getAttributes());
// PrincipalDetails가 만들어져서 Authentication 객체 안에 들어간다.
}
}
Spring은 Application Context의 시작 과정에서 모든 싱글톤 Bean을 즉시 생성하는데, 런타임이 아닌 컴파일 과정에서 모든 가능한 오류를 감지하기 위해서이다.
PrincipalOauth2UserService에서 생성자에 @Lazy어노테이션을 적어 해결해주었다.
@Autowired
private @Lazy BCryptPasswordEncoder bCryptPasswordEncoder;
이처럼 문제가 되는 빈들을 주입 받을 때, @Lazy 어노테이션을 사용해서 지연로딩으로 문제를 해결해준다.
(근데 이제 임시방편의 해결책이라는,,)
설계의 오류로 발생한 문제이기에, 가장 이상적인건 스프링 빈들의 설계를 다시 해서 문제를 해결해주는 것이다.
A -> B, B -> A의 의존관계가 문제가 된다면,
새로운 C를 만들어서 A -> B, B -> C로 문제를 해결해준다.
728x90