Proxy 패턴

이준영·2023년 1월 17일
0

프록시 패턴(Proxy Pattern)

프록시(Proxy)를 번역하면 대리자, 대변인의 의미를 갖고 있다. 대리자, 대변인은 누군가를 대신해서 그 역할을 수행하는 존재이다. 이는 프로그램에도 똑같이 적용된다. 즉, 프록시에게 어떤 일을 대신 시키는 것이다.

  • 핵심 기능은 구현하지 않는다.
  • 여러 객체에 공통으로 적용할 수 있는 기능을 구현한다.

1. Client가 해당 함수를 직접 호출 하는게 아닌 Proxy를 호출

2. Proxy Class에서 실제 Class를 호출합니다. (Proxy Class는 실제로 호출할 Class를 이미 가지고 있다.)

3. 실제 Class에서 반환 받은 값을 Client에게 반환한다.

Proxy Pattern 의 특징은 패턴을 도입함으로 인해 코드를 몇 줄 더 추가하는 일이 있어도 이미 짜여져서 작동하고 있는 코드는 수정하지 않는게 원칙

Proxy 패턴의 장점

  • 사이즈가 큰 객체가 로딩되기 전에도 proxy를 통해 참조를 할 수 있다.
    (이미지, 동영상 등의 로딩에서 반응성 혹은 성능 향상 - 가상 프록시)
  • 실제 객체의 public, protected인 접근제한자 method들을 숨기고 인터페이스를 통해 노출 시킬 수 있다.
    (안전성 - 보호 프록시)

단점

  • 객체를 생성 할 때 한 단계를 거치게 되므로, 빈번한 객체 생성이 필요한 경우 성능이 저하 될 수 있다.
  • Proxy안에서 실제 객체 생성을 위해서 thread가 생성되고 동기화가 구현 되야 하는 경우
    logic이 난해해 질 수 있다

Spring AOP는 Proxy 패턴을 이용해서 AOP를 구현한다.
이는 실제 핵심 기능에는 공통 기능을 추가하지 않고, 따로 클래스를 작성한 뒤 어떤 공통 기능을 어떤 범위에서 사용할 것인지 설정해주면 Spring이 알아서 관리한다.

따라서 소스코드가 간결 해지고 나중에 유지보수를 하거나, 수정사항을 반영할 때 기존 코드를 갈아 엎지 않아도 새로운 기능을 추가하고 기존 기능을 제거하거나 수정하기 훨씬 용이하다.

Proxy객체를 생성하는 방식은 대상 객체가 Interface를 구현하고 있느냐 여부에 달라지게 된다.

위에서는 interface를 기반으로 Proxy를 생성해주는
JDK Dynamic proxy방식이다.

Interface가 구현되지 않았다면 Spring은 CGLIB를 이용하여 클래스에 대한 Proxy객체를 생성한다

JDK Dynamic Proxy

실제 객체와 같은 인터페이스를 사용하는 Proxy 객체를 만든다. 여기서 해당 객체의 Class를 조작해서 런타임에 Proxy 객체 인스턴스를 만든다.

개발자는 Class를 조작하기 위해 InvocationHandler객체의 invoke()메서드만 오버라이딩 한다.
이렇게 Proxy객체를 만들면 특정 메소드나 @Anotation 값에 따라 동적으로 달라지는 Proxy를 만들 수 있다.

즉 JDK Proxy는 인터페이스에 적혀있는 모든 메서드에 Proxy를 적용시키고
Class정보로 조건문을 만들어 특정 메서드만 추가 동작을 하도록 만들 수 있는 것이다.

CGLIB

CGlib는 MethodMatcher 객체를 사용하여 특정 메서드만 Proxy화 하고,
나머지는 프록시를 거치지 않고 실제 객체 메서드를 호출하도록 만들 수 있다.
그 이유는 인터페이스가 아닌 타겟 객체를 직접 상속받아 만들기 때문이다

Spring AOP에 적용

  • [JDK 프록시의 InvocationHandler], [CGlib의 MethodInterceptor]는
    스프링 AOP에서 JoinPoint 개념이다.

  • [JDK 프록시의 조건문], [CGlib의 MethodMatcher]는
    스프링 AOP의 PointCut 개념이다.

  • [JDK invoke 메서드 내용], [CGlib 의 Intercept 메서드 내용]은 스프링 AOP의 Advice 개념이다.

Aspect : 공통 관심사를 모듈화 한 것
Advice : Aspect (공통관심사)의 동작을 적은 것.
Pointcut : 실행 스펙, Pointcut이 일치하는 객체 들에게 Aspect 적용 (조건문)
Join Point : Advice가 적용되는 시점.

Spring boot에서는 전부 CGLIB로 Proxy를 구현한다.

타깃에 대한 정보를 제공 받기 때문에 성능이 좋다는 장점이 있었지만 한계점도 있었다.
최근에 와서야 그 단점들이 줄어들고 있어서 많이 선호

CGLIB 한계점

  • Default 생성자 필요
  • 생성자 2번 호출
  • 의존성을 주입

이러한 한계점을 Objensis 라이브러리와 CGLIB를 Spring core 패키지에 포함시켜서 해결하였다.

Spring은 JDK Dynamic Proxy만 지원했지만
이제는 SpringBoot에서 이러한 한계점을 보완한 CGLIB를 제공

0개의 댓글