///////
Search
👩🏻

순환 참조는 무엇이고 어떤 상황에서 발생할까요?

부제
순환 참조 vs 순환 호출
생성자 주입을 사용해서 순환 참조를 일으키자 !

순환 참조는 무엇일까? (vs 순환 호출)

순환 참조가 발생하면, Spring에서는 위와 같이 에러 화면을 띄어준다.
순환참조 문제란,
A 클래스가 B 클래스의 Bean 을 주입받고,
B 클래스가 A 클래스의 Bean 을 주입받는
상황 같이 서로 순환되어 참조할 경우 발생하는 문제를 의미
의존관계 주입 방식(setter, field, Constructor)과 순환 문제를 섞어서 설명해보자면,
순환 참조 문제
순환 호출 문제
객체 생성 시점에서 순환 참조가 일어나는 것 == 어떠한 Bean도 생성하지 못하는 상태
생성자 주입 사용 시, 런타임 에러
메서드가 순환 호출되며 에러를 일으키는 것
수정자/필드 주입 사용 시, 서버 구동 중에 에러
순환 참조는 런타임 시 잡을 수 있지만, 순환 호출은 잡을 수 없기 때문에 순환 참조 문제를 일으키는 생성자 주입 방식을 권장한다.
어쨋든! 순환 되는 설계를 하지 않는게 중요 하다. 순환 참조건, 순환 호출이건 프로그램 상의 에러를 일으키기 때문에.

어떤 상황에서 일어날까? (코드)

여러 서비스 간에 의존관계가 생기는 경우가 있다. 이때,
Service_1 Service_3 Service_1 이런 의존관계가 생긴다면 순환 참조가 발생한다.

생성자 주입 - 순환 참조

@Service public class ServiceA { private final ServiceB serviceB; @Autowired public ServiceA(ServiceB serviceB) { this.serviceB = serviceB; } } // =========================================== @Service public class ServiceB { private final ServiceA serviceA; @Autowired public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } }
Java
복사
위와 같은 런타임 시에, SpringBoot 구동 에러가 뜬다.
코드를 고치도록 하자.

필드 주입 - 순환 호출

public interface Service_1 { void oneMethod(); } // =================================== @Service public class Service_1Impl implements Service_1 { @Autowired private Service_3 service_3; @Override public void oneMethod() { service_3.threeMethod(); } } // =================================== public interface Service_3 { void threeMethod(); } // =================================== @Service public class Service_3Impl implements Service_3 { @Autowired private Service_1 service_1; @Override public void threeMethod() { service_1.oneMethod(); } }
Java
복사
위의 코드는 StackOverflowError를 발생시킨다.
그런데, 스프링 애플리케이션 구동은 잘 되는데, 실제 코드가 호출 될때 (사용자가 사용할 때) 죽는다...
필드 주입이나, 수정자 주입은 객체 생성시점에는 순환참조가 일어나는지 아닌지 발견할 수 있는 방법이 없기 때문이다.