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

31. 로그트레이스 프록시 적용

sdafdq 2024. 1. 19. 17:48

기존에, 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();
	}

}

이렇게 추가로 빈으로 등록 해 줬다.