목차
1. BeanCurrentlyInCreationException 왜 발생할까?
2. 어떻게 해결할까?
1. BeanCurrentlyInCreationException 왜 발생할까?
프로젝트가 커짐에 따라 아래와 같은 예외를 만난 경험이 있을수도 있다. 저는 AOP를 공부하다가 해당 예외를 마주하게 되었습니다.
예외의 마지막 줄을 해석해보면 해결할 수 없는 순환 참조(circular reference)가 있는건 아닌지 말해주네요. 그러면 스프링에서 순환 참조란 무엇일까요?
스프링 컨테이너에서는 객체를 생성하고 스프링 빈으로 등록합니다. 스프링 빈으로 등록할 때는 의존 관계를 주입해야 합니다. 이 과정에서 순환 참조가 발생하게 됩니다. 그럼 순환 참조란 무엇일까요? 쉬운 예시를 통해 이해해봅시다.
쉽게 말해 서로가 서로를 필요로하는 것입니다.
1. SimpleService를 스프링 빈으로 등록하기 위해서 SimpleEvent가 필요해요.
2. 그래서 SimpleEvent을 스프링 빈으로 등록하려고 합니다.
3. 그런데 SimpleEvent를 스프링 빈으로 등록하기 위해서는 SimpleSerivce가 필요합니다.
4. 1,2,3 무한 반복
2. 어떻게 해결할까?
검색을 해보면 여러가지 해결책이 있습니다. 하지만 스프링에서 권장하는 몇 가지가 있는데요. 첫 째는 생성자 주입입니다. 순환 참조 문제를 해결하려다 보면 세터 주입을 사용해야할 수도 있습니다. 이 외에도 여러 방법들을 찾을 수 있는데요. 조금 어렵더라구요.
가장 깔끔한 방법은 순환 참조를 끊는 것입니다. 사실 생각해보면 순환 참조는 필요가 없거든요. 위 사례에서 보면 SimpleService, SimpleEvent는 서로를 필요로 하는데요. 서로를 필요로 하다는 건 SimpleService, SimpleEvent 두 개가 분리될 필요가 없을 수도 있다는 뜻일수도 있습니다.
그럼 제가 진행한 프로젝트에서 순환 참조를 끊어보겠습니다. 문제의 원인 중 하나인 ExeTimeAspect입니다. 해당 클래스는 스프링 빈으로 등록됩니다.
주목할 것은 포인트 지시자입니다. chap07과 그 내부에 있는 모든 클래스에 Advice를 적용합니다. 패키지 구조는 아래와 같습니다. AppCtx, CacheAspect 등 가릴 것 없이 Aspect가 적용됩니다.
문제의 원인 두번 째 AppCtx입니다. 설정 파일이지만 @Configuration 내부에도 @Component가 존재하기 때문에 스프링 빈으로 등록됩니다.
원인 2개가 모여 순환참조가 발생합니다. 서로가 서로를 필요하게 됩니다.
이제 정말로 순환참조를 끊어보겠습니다. 1. 패키지 구조 변경, 2. 포인트컷 지시자 변경으로 문제를 해결하겠습니다.
1. 패키지 구조 변경
변경 전 패키지 구조를 보면 chap07 내부에 AppCtx가 존재하는데요. 이로 인해 Advice 대상이 됩니다. 대상이 되지 않도록 패키지 구조를 아래와 같이 변경하겠습니다.
위와 같이 AppCtx를 chap07 밖으로 빼줍니다. 그러면 Advice 대상이 되지 않아 의존할 필요가 없게됩니다.
2. 포인트컷 지시자 변경
이번에는 패키지 구조를 변경하는대신 포인트컷을 변경해보도록 하겠습니다.
위 주석을 아래 빨간 박스와 같이 변경해주면 AppCtx가 Advice 대상에서 제외되기 때문에 순환 참조가 발생하지 않습니다.
'Spring > core' 카테고리의 다른 글
HandlerAdapter (1) | 2023.04.08 |
---|---|
프록시 내부 호출 문제 해결 방법 - 자기 주입, 지연 조회, 구조 변경 (0) | 2023.03.26 |
스프링5 프로그래밍 입문 - ch7. AOP 프로그래밍 - (2) AOP (0) | 2023.03.25 |
스프링5 프로그래밍 입문 - ch7. AOP 프로그래밍 - (1) 프록시 (0) | 2023.03.25 |
스프링5 프로그래밍 입문 - ch6.빈 라이프사이클 (0) | 2023.03.24 |