스프링/스프링 핵심 원리 - 고급편

33. 구체클래스 프록시 적용

sdafdq 2024. 1. 19. 19:40
public class OrderServiceConcreteProxy extends OrderServiceV2 {
    private final OrderServiceV2 target;
    private final LogTrace logTrace;

    public OrderServiceConcreteProxy(OrderServiceV2 target, LogTrace logTrace) {
        super(null);
        this.target = target;
        this.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;
        }
    }
}

그냥 상속받아서 만들면 된다.

 

그런데, 생성자 부분.

 

자식은 부모의 요소들을 포함하고 있어야 하기 때문에, 부모의 생성자를 한번 호출해서 만들어야 한다.

 

근데 이것은 프록시로 쓸 것이라 상관이 없다.

 

그래서 기존에 Repository 넣어야 했었는데 딱히 부모의 메소드나 필드를 쓸 것이 아니고

다형성만 활용할 것 이기 때문에, null로 했다.

 

그리고, target과 logTrace 받고,

 

필요에 따라 @Override 해 줬다.

 

 

public class OrderRepositoryConcreteProxy extends OrderRepositoryV2 {
    private final LogTrace logTrace;
    private final OrderRepositoryV2 target;

    public OrderRepositoryConcreteProxy(LogTrace logTrace, OrderRepositoryV2 target) {
        this.logTrace = logTrace;
        this.target = target;
    }

    @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;
        }
    }
}

 

 

 

 

public class OrderControllerConcreteProxy extends OrderControllerV2 {
    private final LogTrace logTrace;
    private final OrderControllerV2 target;

    public OrderControllerConcreteProxy(LogTrace logTrace, OrderControllerV2 target) {
        super(null);
        this.logTrace = logTrace;
        this.target = target;
    }

    @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();
    }
}

 

 

 

@Configuration
public class ConcreteProxyConfig {

    @Bean
    public OrderControllerV2 orderControllerV2(LogTrace logTrace){
        OrderControllerV2 controllerImpl = new OrderControllerV2(orderServiceV2(logTrace));
        return new OrderControllerConcreteProxy(logTrace, controllerImpl);
    }

    @Bean
    public OrderServiceV2 orderServiceV2(LogTrace logTrace){
        OrderServiceV2 serviceImpl = new OrderServiceV2(orderRepositoryV2(logTrace));
        return new OrderServiceConcreteProxy(serviceImpl, logTrace);
    }

    @Bean
    public OrderRepositoryV2 orderRepositoryV2(LogTrace logTrace){
        OrderRepositoryV2 repositoryImpl = new OrderRepositoryV2();
        return new OrderRepositoryConcreteProxy(logTrace, repositoryImpl);
    }
}

이 부분. 

 

사실 인터페이스 때랑 똑같다.

 

프록시에 구체클래스(원본)을 주면서 활용하는 것, 또 그 원본은 프록시를 가지고 있어야 프록시 기능을 호출할 수 있다는 것.

이거랑 똑같다.

위쪽이 프록시, 아래쪽이 기능 구현체.