기존에, v1 버전은 애초에 모두 인터페이스로 만들어 뒀었다.
public interface OrderRepositoryV1 {
void save(String itemId);
}
이런 식으로.
이제 이거를 프록시로 새로 만들면 된다.
public class OrderServiceV1Impl implements OrderServiceV1{
private final OrderRepositoryV1 orderRepository;
public OrderServiceV1Impl(OrderRepositoryV1 orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public void orderItem(String itemId) {
orderRepository.save(itemId);
}
}
먼저 기존의 구현체도 이렇게 만들어 뒀었고,
@RequiredArgsConstructor
public class OrderServiceInterfaceProxy implements OrderServiceV1 {
private final OrderServiceV1 target;
private final LogTrace logTrace;
@Override
public void orderItem(String itemId) {
TraceStatus status = null;
try{
status = logTrace.begin("OrderService.orderItem()");
target.orderItem(itemId);
logTrace.end(status);
} catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
}
프록시는 이렇게 원본을 가지면서, 앞뒤로 미사여구를 붙인다.
기능을 추가하다 원본의 핵심 로직이 필요한 순간 원본으로 호출하면 된다.
@RequiredArgsConstructor
public class OrderControllerInterfaceProxy implements OrderControllerV1 {
private final OrderControllerV1 target;
private final LogTrace logTrace;
@Override
public String request(String itemId) {
TraceStatus status = null;
try{
status = logTrace.begin("OrderController.request()");
String result = target.request(itemId);
logTrace.end(status);
return result;
} catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
@Override
public String noLog() {
return target.noLog();
}
}
@RequiredArgsConstructor
public class OrderRepositoryInterfaceProxy implements OrderRepositoryV1 {
private final OrderRepositoryV1 target;
private final LogTrace logTrace;
@Override
public void save(String itemId) {
TraceStatus status = null;
try{
status = logTrace.begin("OrderRepository.request()");
target.save(itemId);
logTrace.end(status);
} catch (Exception e){
logTrace.exception(status, e);
throw e;
}
}
}
그리고 이제 빈 등록. 사실 이 부분이 중요하다.
@Configuration
public class InterfaceProxyConfig {
@Bean
public OrderControllerV1 orderController(LogTrace logTrace){
OrderControllerV1Impl orderControllerImpl = new OrderControllerV1Impl(orderService(logTrace));
return new OrderControllerInterfaceProxy(orderControllerImpl, logTrace);
}
@Bean
public OrderServiceV1 orderService(LogTrace logTrace) {
OrderServiceV1Impl orderServiceImpl = new OrderServiceV1Impl(orderRepository(logTrace));
return new OrderServiceInterfaceProxy(orderServiceImpl, logTrace);
}
@Bean
public OrderRepositoryV1 orderRepository(LogTrace logTrace) {
OrderRepositoryV1Impl orderRepositoryImpl = new OrderRepositoryV1Impl();
return new OrderRepositoryInterfaceProxy(orderRepositoryImpl, logTrace);
}
}
프록시는 원본을 가진다.
그래서 먼저 원본부터 생성을 해 주고, 그 원본을 프록시 안에 넣어준다.
그리고, 그 원본이 결국 다른 하위의? Service 등의 메소드를 호출하는 것 이므로, 원본이 프록시 상태의 Service 등을 가지고 있는거다.
이렇게 보면 된다.
위쪽이 프록시고, 아래쪽이 원본임.
로그 트레이스는,
@Import(InterfaceProxyConfig.class)
@SpringBootApplication(scanBasePackages = "hello.proxy.app") //주의
public class ProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ProxyApplication.class, args);
}
@Bean
public LogTrace logTrace(){
return new ThreadLocalLogTrace();
}
}
이렇게 추가로 빈으로 등록 해 줬다.
'스프링 > 스프링 핵심 원리 - 고급편' 카테고리의 다른 글
33. 구체클래스 프록시 적용 (0) | 2024.01.19 |
---|---|
32. 구체 클래스에 프록시 적용 (0) | 2024.01.19 |
30. 데코레이터 패턴 (0) | 2024.01.19 |
29. 프록시 패턴 (0) | 2024.01.19 |
28. 프록시 패턴과 데코레이션 패턴 (0) | 2024.01.19 |