순환참조 오류(spring circular reference)

문정현·2024년 1월 4일
0

순환참조 오류

스프링 DI를 구성할 때 항상 순환참조 오류를 조심해야 한다

순환참조는 어느 스프링 빈을 먼저 생성할지 결정하지 못하기 때문에 발생한다
1. 생성자 주입방식
2. 필드 주입방식
3. setter 주입방식

이 세가지의 상황에서 발생하는데 하나씩 살펴보자

생성자 주입방식

@Component
public class BeanA {
	private BeanB beanB;

	public void BeanA(BeanB beanB){
		this.beanB = beanB;
	}
}

@Component
public class BeanB {
	private BeanA beanA;

	public void BeanB(BeanA beanA){
		this.beanA = beanA;
	}
}

스프링 컨테이너가 BeanA를 생성하기 위해 BeanB를 주입해야한다 -> BeanB를 생성하려고 하니 BeanA를 주입하기 위해 다시 BeanA를 찾는다 -> 무한 반복

필드 주입방식과 setter 주입방식

필드 주입

@Component
@Slf4j
public class BeanA {
	@Autowired
	private BeanB beanB;

	public void run(){
		beanB.run();
	}

	public void call(){
		log.info("called BeanA");
	}
}

@Component
@Slf4j
public class BeanB {
	@Autowired
	private BeanA beanA;

	public void run(){
		log.info("Called BeanB");
		beanA.call();
	}
}

setter 주입방식

@Component
@Slf4j
public class BeanA {
	private BeanB beanB;

	@Autowired
	public void setBeanB(BeanB beanB){
		this.beanB = beanB;
	}

	public void run(){
		beanB.run();
	}

	public void call(){
		log.info("called BeanA");
	}
}

@Component
@Slf4j
public class BeanB {
	private BeanA beanA;

	@Autowired
	public void setBeanA(BeanA beanA){
		this.beanA = beanA;
	}

	public void run(){
		log.info("Called BeanB");
		beanA.call();
	}
}

두 방식 모두 생성자 주입방식과 달리 어플리케이션 구동 당시에는 순환참조 오류가 발생하지 않지만 메서드를 호출하는 시점에서 순환참조 오류를 일으킬 수 있으면 문제가 발생한다

해결책

@Lazy
해결책으로 @Lazy 어노테이션을 통해 초기화를 지연시켜 순환 참조를 끊을 수 있지만 어플리케이션의 성능적인 문제와 빈을 초기화 되는 시점에 JVM의 메모리공간이 충분한지 불분명하다는 단점이 있기에 스프링에서 권장하지 않는다

그렇다면?
먼저 entity를 분리하고 dto나 recode와 같은 데이터를 전달해줄 객체에 담아서 request, response를 구성한다
메소드를 설계할 때 bean 서로를 참조하지 않도록 신경쓰자..

profile
주니어 개발자를 꿈꾸며

0개의 댓글