ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 프록시를 이용한 로그추적기 - 인터페이스 기반
    스프링/스프링 AOP 2023. 9. 10. 22:13

    기존에 있던 로그 추적기는 코드를 하나씩 전부 바꿔야했는데 프록시를 이용하면 그렇게 하지 않고 스프링 빈으로 등록할 때 프록시를 스프링 빈으로 등록해주면 된다.

     

    로그 추적기 코드는 저번 포스팅에 이미 있어서 여기에는 올리지 않을테니 로그 추적기 관련 포스팅을 같이 보면 된다.

     

     

    OrderRepositoryInterfaceProxy

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

    저번에 했던 로그 추적기 그대로 try_catch문 안에서 target.save(item) 로직으로 target을 호출한다. target이 실제 객체인 것이고, 프록시를 거치고 나서 실제 객체를 호출하는 것이다.

     

    Service와 Controller 계층도 Repository와 동일하게 진행되니 설명을 생략하겠다.

     

     

    OrderServiceInterfaceProxy

    @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.request()");
                target.orderItem(itemId);
                logTrace.end(status);
            } catch (Exception e) {
                logTrace.exception(status, e);
                throw e;
            }
        }
    }

     

     

    OrderControllerInterfaceProxy

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

     

     

    위의 프록시 객체들도 실제 객체를 호출한다.

     

    사진 : 인프런 스프링 강의

    위의 사진처럼 프록시를 호출한 다음에 프록시는 실제 객체를 호출하고, 실제 객체는 다음 단계의 프록시를 호출한다. 물론 Service의 실제 객체는 Repository를 호출하는데 사진에는 안나와있다.

     

    위와 같은 방식을 사용하려면 Configuration에서 스프링 빈을 등록해주면 된다.

     

    InterfaceProxyConfig

    @Configuration
    public class InterfaceProxyConfig {
    
        @Bean
        public OrderControllerV1 orderController(LogTrace logTrace) {
            OrderControllerV1Impl controllerImpl = new OrderControllerV1Impl(orderService(logTrace)); // target
            // orderService가 파라미터인데 orderService는 프록시를 반환함
            return new OrderControllerInterfaceProxy(controllerImpl, logTrace);
        }
    
        @Bean
        public OrderServiceV1 orderService(LogTrace logTrace) {
            OrderServiceV1Impl serviceImpl = new OrderServiceV1Impl(orderRepository(logTrace));
            return new OrderServiceInterfaceProxy(serviceImpl, logTrace);
        }
    
        @Bean
        public OrderRepositoryV1 orderRepository(LogTrace logTrace) {
            OrderRepositoryV1Impl repositoryImpl = new OrderRepositoryV1Impl();
            return new OrderRepositoryInterfaceProxy(repositoryImpl, logTrace);
        }
    }

    위의 사진처럼 클라이언트가 컨트롤러를 호출하면 컨트롤러를 반환해주는 것이 아니라, 컨트롤러 프록시 객체를 반환해준다. 컨트롤러 프록시 객체는 컨트롤러 실제 객체를 호출하게 된다.

     

    orderService 또한 프록시 객체를 반환하고, 컨트롤러에서 OrderControllerV1Imple의 파라미터로 들어가는 orderService는 프록시 객체인 것이다.

     

    같은 방식으로 Repository도 진행된다.

     

    결국 모든 스프링 빈은 LogTrace를 받으며, 각각의 프록시 객체를 호출하는 것이다.

     

    클라이언트는 컨트롤러의 프록시 객체 호출 -> 컨트롤러는 서비스의 프록시 객체 호출 -> 서비스는 리포지토리의 프록시 객체 호출

     

     

    configuration에서는 실제 객체를 스프링 빈으로 등록하지 않고 프록시를 대신 등록하게 된다. 프록시 객체안에 실제 객체가 있는 것이라 생각하면 편하다.

    이 기술의 가장 큰 장점은 기존 비즈니스 로직의 코드는 하나도 건들이지 않고 호출하는 과정에서 프록시 객체를 앞에 주입시켜 주었다는 것이다.

     

    로그 추적기와 같은 부가적인 기능은 프록시를 이용하면 기존보다 더 효율적으로 할 수 있게 된다.

     

     

    클래스 기반 프록시도 존재하지만 클래스 기반 프록시는 상속을 사용하기 때문에 몇 가지 제약이 있기 때문에 인터페이스 기반 프록시를 사용한다고 한다.

    물론 인터페이스를 무조건 만들어야 한다는 단점이 있다. (캐스팅 관련해서 단점도 존재한다.)

Designed by Tistory.