인터페이스 기반 프록시

종원유·2022년 3월 14일
0

Spring

목록 보기
10/10

인터페이스 기반 프록시

인터페이스를 기반으로 기존 코드 수정없이 프록시를 도입하는 방법을 정리하려한다.

인터페이스를 기반으로 프록시를 적용한다면 너무나도 당연한 얘기지만,

  • 의존 관계들이 인터페이스를 의존해야 한다.

프록시 적용

프록시 적용 전


//Controller
@Slf4j
@RestController
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @GetMapping("/request")
    public String request(String itemId) {
        orderService.orderItem(itemId);
        return "ok";
    }

}

//Service
public interface OrderService {
    String orderItem(String itemId);
}

//Service
@Slf4j
@Service
public class OrderServiceImpl implements OrderService{
    @Override
    public String orderItem(String itemId) {
      log.info("Service Process");
      return "data : " + itemId;
    }
}

//Bean 설정 

@Configuration
public class SelfConfig {

    @Bean
    public OrderController orderController(){
        return new OrderController(orderService());
    }

    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl();
    }
}

위 Controller -> Service 구조를 인터페이스 기반 프록시를 적용해보자

프록시 적용 후

구현체와 프록시는 같은 인터페이스를 구현한다.



@Configuration
public class SelfConfig {

    @Bean
    public OrderController orderController(){
        return new OrderController(orderService());
    }

    @Bean
    public OrderService orderService(){
        return new OrderProxy(new OrderServiceImpl()); //수정
    }

}

//proxy
@Slf4j
@RequiredArgsConstructor
public class OrderProxy implements OrderService{

    private final OrderService target;

    @Override
    public String orderItem(String itemId) {
        log.info("Proxy호출");
        return target.orderItem(itemId);
    }
}

기존에는 실제 구현 객체를 반환했지만, 프록시를 사용할 경우 프록시를 생성해서 반환하도록 하여 실제 스프링 빈 대신 등록해야 한다.
실제 객체는 스프링 빈으로 등록하지 않는다.

    @Bean
    public OrderService orderService(){
        return new OrderProxy(new OrderServiceImpl()); //수정
    }

또, Proxy는 target(OrderServiceImpl)으로 실제 객체를 참조한다.

    private final OrderService target;

Proxy를 스프링 빈으로 등록하고 Proxy에서 실제 객체를 참조할 경우 프록시 객체는 스프링 컨테이너가 관리하고 자바 힙 메모리에도 올라간다. 반면 실제 객체는 자바 힙 메모리에는 올라가지만 스프링 컨테이너 관리 대상이 아니다.

  • Proxy : 힙 메모리 O, 스프링 컨테이너 관리 대상 O
  • 실제객체 : 힙 메모리 O, 스프링 컨테이너 관리 대상 X

  • 출력 결과

Client -> Proxy -> Service 런타임 의존 관계가 완성되었다.
인터페이스를 기반으로 프록시를 적용하여 기존 로직 수정없이 Decorator 패턴을 적용하여 추가 기능을 적용하였다.

정리

  • Proxy -> target (OrderProxy -> OrderServiceImpl)
  • 스프링 빈으로 실제 객체 대신에 프록시 객체를 등록했기 때문에 앞으로 스프링 빈을 주입 받으면 실제 객체 대신에 프록시 객체가 주입된다.
  • 실제 객체가 스프링 빈으로 등록되지 않는다고 해서 사라지는 것은 아니다. 프록시 객체가 실제 객체를 참조하기 때문에 프록시를 통해서 실제 객체를 호출할 수 있다. 쉽게 이야기해서 프록시 객체 안에 실제 객체가 있는 것이다.

인터페이스 프록시 도입 시 고려할 부분

  • 인터페이스를 도입하는 것은 구현을 변경할 가능성이 있을 때 효과적이다.
  • 구현을 변경할 가능성이 거의 없는 코드에 무작정 인터페이스를 사용하는 것은 번거롭고 실용적이지 않다.

인터페이스를 무작정 도입하는 것은 좋지 않다.
구현의 변경이 없을 경우는 구체 클래스를 바로 사용하는 것이 좋을 수 있다.

profile
개발자 호소인

0개의 댓글