Web/Spring

[Spring] Spring Bean 순환 참조 오류

땀두 2022. 4. 6. 19:32

AOP 관련 실습을 해보기 위해서 Component Scan방식을 활용하여 아래와 같이 Spring Config에 AOP 객체를 추가하였다.

 

그리고 프로젝트를 빌드하여 실행하였는데 아래와 같은 오류가 발생하였다.

이러한 오류는 스프링 빈 순환참조(Circular dependencies) 때문에 생기는 것이다.

스프링 빈 순환참조 오류란 스프링 document에서 내용을 확인할 수 있다.

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-dependency-resolution

 

Core Technologies

In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do

docs.spring.io

 

내용을 번역하면 아래와 같다.

 

순환 종속성은 주로 생성자 주입을 사용하는 경우 해결할 수 없는 순환 종속성 시나리오를 만들 수 있습니다.

 

예: 클래스 A는 생성자 주입을 통해 클래스 B의 인스턴스가 필요하고 클래스 B는 생성자 주입을 통해 클래스 A의 인스턴스가 필요하다. 클래스 A와 B의 빈을 서로 주입하도록 구성하면 Spring IoC 컨테이너는 런타임에 이 순환 참조를 감지하고 BeanCurrentlyInCreationException을 발생시킨다.

한 가지 가능한 솔루션은 생성자가 아닌 설정자에 의해 구성되도록 일부 클래스의 소스 코드를 편집하는 것이다. 대안으로는 생성자 주입을 피하고 setter 주입을 사용하면 된다. 즉, 권장하지는 않지만 setter 주입으로 순환 종속성을 구성할 수 있다는 뜻이다.

순환 종속성이 없는 일반적인 경우와 달리 빈 A와 빈 B 사이의 순환 종속성은 자체적으로 완전히 초기화되기 전에 빈 중 하나가 다른 빈에 주입되도록 합니다(고전적인 닭과 달걀 시나리오).

 

쉽게 말하자면 A라는 클래스에서 B라는 클래스를 인스턴트로 필요로하고, B라는 클래스에서도 A라는 클래스를 인스턴트로 필요한 경우 서로가 서로를 참조하게 되면서 에러가 발생하는 것이다. 

 

위 코드의 경우를 다시 살펴보면

 @Bean//component scan으로 해도 되지만 직관적으로 보기 위해서 추가
    public TimeTraceAop timeTraceAop(){
        return new TimeTraceAop();
    }

 

이렇게 Bean에서 TimeTraceAop을 선언했고, TimeTraceAop의 코드로 가보게 되면 아래와 같이 Around의 범위에서 또 TimeTraceAop를 AOP로 처리하게 되어있다.

@Aspect
public class TimeTraceAop {
    @Around("execution(* com.example.demo..*(..))")
...

그렇기 때문에 AOP로 계속적으로 TimeTraceAop의 코드를 불러오기 때문에 순환참조 문제가 발생한다고 볼 수 있다.

 

이러한 점을 해결하기 위해서는 Component Scan방식으로 직접 TimeTraceAop를 등록해주는 방법이 있고, Around의 범위에서 SpringConfig를 제외시켜주는 방법이 있다.