일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 현금흐름표
- 금리인상
- 그리디 알고리즘
- 주린이
- 자바
- 배당성장
- 프로그래머스
- 객체지향
- FCF
- 잉여현금흐름
- 금리인하
- XLF
- mco
- javascript
- 기업분석
- 미국주식
- object
- Java
- S&P500
- 알고리즘
- 다형성
- 인플레이션
- 주식
- etf
- 백준
- 접근제어자
- 제태크
- 오버라이딩
- 무디스
- StringBuffer
- Today
- Total
오늘의하루
[Spring] Proxy 내부 호출 문제 해결 및 순환 참조 문제 해결 본문
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이기 때문에 내부 객체를 호출하지만 어드바이스가 적용되는것을 확인할 수 있습니다.
'Spring' 카테고리의 다른 글
[Spring] Thread Local 사용 시 주의 사항 (0) | 2024.08.03 |
---|---|
[Spring] 부하 테스트에서 발견한 회원가입 로직 이상 동작에 대한 고찰 (0) | 2024.05.16 |
Spring 서비스 추상화와 단일 책임 원칙 (0) | 2023.10.16 |
Spring boot 오류 페이지 (0) | 2023.08.30 |
Servlet의 예외 처리하는 방법 (0) | 2023.08.30 |