🔹Spring의 프록시 개념
Spring 프레임워크는 비동기 실행(@Async), 트랜잭션(@Transactional), AOP(@Aspect) 등 다양한 기능을 제공할 때 프록시(proxy) 객체를 활용한다.
🔸프록시 객체란?
프록시 객체는 원본 객체를 감싸는 대리 객체로, 메서드 호출을 가로채고 추가적인 기능을 수행할 수 있다.
Spring에서 @Async 기능을 적용할 때의 예시를 살펴보자
@Service
public class PatientScheduleService {
@Async
public void asyncMethod() {
System.out.println("비동기 실행"); // 프록시 객체를 통해 호출됨 → 비동기 실행됨
}
}
- Spring이 PatientScheduleService를 Bean으로 등록할 때, 프록시 객체를 생성하여 관리한다.
- asyncMethod()가 호출되면, 프록시 객체가 이를 가로채고 새로운 스레드에서 실행한다.
- 결과적으로 patientService.checkStatus()는 비동기적으로 실행된다.
만약 같은 클래스내에서 asyncMethod()를 직접 호출하면 어떻게 될까?
@Service
public class PatientScheduleService {
@Async
public void asyncMethod() {
System.out.println("비동기 실행"); // 프록시 객체를 통해 호출됨 → 비동기 실행됨
}
public void testAsyncCall() {
asyncMethod(); // 같은 클래스 내에서 직접 호출 → 동기 실행됨
}
}
testAsyncCall()에서 asyncMethod()를 호출하면, 프록시가 아닌 현재 객체(this)의 메서드를 호출한다. 따라서 asyncMethod()는 비동기로 실행되지 않고, 동기적으로 실행된다.
왜냐하면 프록시 객체는 외부에서 메서드를 호출할 때만 동작한다. 같은 클래스 내부에서는 프록시를 거치지 않는 것이다.
같은 클래스에서 @Async를 올바르게 호출하는 방법
1. ApplicationContext를 이용해 프록시 객체 가져오기
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
@RequiredArgsConstructor
@Service
public class PatientScheduleService {
// ApplicationContext 주입
private final ApplicationContext context;
@Async
public void asyncMethod() {
System.out.println("비동기 실행"); // 프록시 객체를 통해 호출됨 → 비동기 실행됨
}
public void testAsyncCall() {
PatientScheduleService proxy = context.getBean(PatientScheduleService.class);
proxy.asyncMethod(); // 프록시 객체를 통해 호출 → 비동기 실행됨
}
}
방법 2: @Autowired로 자기 자신을 주입받아 사용하기
@Service
public class PatientScheduleService {
@Autowired
private PatientScheduleService patientScheduleService; //자기자신 주입
@Async
public void asyncMethod() {
System.out.println("비동기 실행");
}
public void testAsyncCall() {
patientScheduleService.asyncMethod(); // 프록시 객체를 통해 호출 → 비동기 실행됨
}
}
하지만 자기 자신을 주입해 사용하게 되면 순환참조 문제가 발생할 수 있으므로, @Lazy와 같은 옵션을 같이 사용하는 것을 권장한다고 한다.
'Spring' 카테고리의 다른 글
다이나믹 프록시(Dynamic Proxy)로 부가 기능 적용하기 (1) | 2025.03.16 |
---|---|
[Spring] 비동기 처리: @Async, @EnableAsync (0) | 2025.03.12 |
멀티 Thread 테스트 : ExecutorService / CountDownLatch (1) | 2025.03.11 |
페이지네이션(Pagination) - 오프셋 기반, 커서 기반, Slice vs Page (0) | 2025.02.27 |
[SpringBoot] OpenAI API 적용하기 (0) | 2024.08.07 |