-
[Spring] Proxy 내부 호출 문제 해결 및 순환 참조 문제 해결Development/Spring 2024. 8. 28. 17:35728x90반응형
Proxy 내부 호출
@Component @Slf4j public class A { public void external() { log.info("external"); internal(); } public void internal() { log.info("internal"); } } --- @Aspect @Slf4j public class AllAspect { @Before("execution(* *(..))") public void doA(JoinPoint joinPoint) { log.info("aop = {}", joinPoint.getSignature()); } }위 상황에서 external()을 호출하면 doA 메서드에서 작성한 로그는 external()에서만 출력됩니다.
이는 Spring이 Proxy 방식을 사용하여 AOP를 적용하기 때문입니다. Proxy 객체는 external() 호출을 처리한 후 실제 객체의 internal() 메서드를 호출하기 때문에 internal() 메서드에서는 AOP가 적용되지 않습니다.
이를 해결하기 위해서는 external()에서 internal()을 호출할 때 this가 아닌 Proxy 객체를 사용해야 합니다.
Proxy 객체를 사용한 해결 방법
@Component public class A { private A a; @Autowired public void setB(A a) { this.a = a; } public void external() { log.info("external"); a.internal(); } public void internal() { log.info("internal"); } }위 코드에서는 external()에서 internal()을 호출할 때 Proxy 객체를 사용하도록 설정했습니다.
Setter 주입을 사용한 이유는 아직 초기화되지 않은 객체를 생성자 주입으로 처리할 수 없기 때문입니다.
Setter 주입은 생성자 주입보다 늦게 초기화되므로 이러한 순환 참조 문제를 해결할 수 있습니다.
하지만 SpringBoot 2.6 이상에서는 기본적으로 이러한 순환 참조가 금지되어 있습니다.
만약 위와 같은 방식으로 진행하려면 application.properties에 다음 설정을 추가해야 합니다:
spring.main.allow-circular-references=true설정 없이 해결하는 방법
Spring에서는 @Lazy와 ObjectProvider를 사용하여 순환 참조 문제를 해결할 수 있습니다.
@Lazy
JPA를 공부하면서 Lazy는 지연 로딩에서 사용한다는 것을 듣고 해당 어노테이션을 보니 이해가 잘 되었습니다.
@Lazy는 의존성 주입을 지연시켜 생성자 주입보다 이후에 주입이 이루어지도록 합니다.
이로 인해 순환 참조 문제를 해결할 수 있습니다.
@Component public class A { privat A a; @Autowired public A (@Lazy A a) { this.a = a; } ... method ... }ObjectProvider
ObjectProvider는 스프링에서 제공해주는 빈을 컨테이너에 요청하면 찾아주는 기능을 제공합니다.
@Component public class A { private final ObjectProvider<A> aProvider; @Autowired public A (ObjectProvider<A> aProvider) { this.aProvider = aProvider; } public void external() { log.info("external"); A a = aProvider.getObject(); a.internal(); } }AOP를 통해 빈 컨테이너에 저장된 객체는 Proxy이기 때문에 getObject()를 통해 찾은 객체 또한 Proxy이기 때문에 내부 객체를 호출하지만 어드바이스가 적용되는것을 확인할 수 있습니다.
728x90반응형'Development > Spring' 카테고리의 다른 글
DTO(Data Transfer Object)를 쓰는 이유? (1) 2024.11.11 BeanPostProcessor 사용법: 빈 초기화 과정에서의 조작과 시점 이해하기 (0) 2024.11.07 [Spring] Thread Local 사용 시 주의 사항 (0) 2024.08.03 [Spring] 부하 테스트에서 발견한 회원가입 로직 이상 동작에 대한 고찰 (0) 2024.05.16 Spring 서비스 추상화와 단일 책임 원칙 (0) 2023.10.16