Proxy and Proxy pattern?

Proxy?

Proxy

Proxy는 대리자, 대리인의 뜻을 지닌다. 이처럼 어떤 요청을 주었을 때, 요청 받을 대상 대신에 나서서 처리를 하는 대상을 Proxy라고 지칭한다. 일반적으로 Proxy라는 용어는 클라어언트와 사용 대상 사이에 대리 역할을 맡은 오브젝트를 두는 방법을 총칭하는데, 디자인 패턴에서 이야기하는 Proxy pattern은 Proxy를 사용하는 방법 중에서 타깃에 대한 접근 방법을 제어하려는 목적을 가진 경우를 가리킨다.

여기서 Proxy와 Target에 대한 이야기가 나오는데, Target은 사용자가 사용하려는 실제 비지니스 로직을 구현한 클래스나 인터페이스를 이야기한다.

만일, User와 관련된 비지니스 로직을 처리하는 UserServiceImpl 이라는 클래스가 있다면, 비지니스 로직을 처리하기 전, 트랜잭션과 같은 부가기능을 추가하기 위해서 UserServiceTx와 같은 트랜잭션을 처리하는 구현체를 두고, 이를 UserService인 것 마냥 사용자에게 사용하도록 한다.

여기서에서 UserServiceImpl이 Target의 역할, UserServiceTx가 프록시 역할을 하는 것이다. 사용자는 UserService 인터페이스를 구현한 구현체가 당연히 사용자 정보에 관련된 비지니스 로직을 처리한다고 생각하지만, 실제로 사용자가 호출하는 객체는 UserServiceTx 클래스이고, UserServiceTx가 UserServiceImpl을 호출해서 비지니스 로직을 처리하도록 하는 것이다.

Proxy pattern?

ProxyPattern

Proxy pattern이란, 실제 사용되는 객체의 생성이나 레퍼런스를 대리인, 즉 Proxy 객체가 정해주는 디자인 패턴을 말한다. 쉽게 이야기하면 사용자는 Proxy를 Target 오브젝트 대신에 넘겨주고, 실제 Target 오브젝트가 필요할때는 Proxy객체가 Target 오브젝트를 필요할 때 생성해서 사용하도록 하는 방법이다.

이렇게 Proxy 객체가 Target 오브젝트를 필요할 때 생성해서 사용하도록 하면, 사용자 쪽에서 레퍼런스를 가지고는 있지만 사용하지 않는 경우나 많은 작업이 진행된 이후에 적은 숫자로 Target 오브젝트를 사용하는 경우에 이점을 얻을 수 있다.

Proxy pattern은 실제 Target 오브젝트의 기능에는 관여하지 않으면서, Target 오브젝트에 접근하지 위한 방법을 제어해주는 역할을 한다. Decorator pattern과 비슷하지만, Proxy pattern은 자신이 만들거나 접근할 Target 클래스의 정보를 알고있는 경우가 많다.

물론, Proxy pattern은 Decorator pattern과 같이 적용할 수 있다. Proxy를 이용하여 접근 제어에 관한 일을 처리하도록 하고, Decorator를 붙여서 부가기능을 수행하도록 하는 것이다.

Dynamic Proxy

Dynamic Proxy는 런타임시에 Proxy Factory에 의해서 만들어지는 Proxy용 오브젝트다. Dynamic proxy는 Target 오브젝트와 같은 타입으로 만들어지기 때문에, Proxy factory에 인터페이스의 정보만 전달해주면 해당 타입에 맞는 Proxy 오브젝트를 만들어준다.

InvocationHanlder

그렇지만 Proxy의 필요한 부가기능에 관한 코드는 직접 작성해야 한다. 작성한 부가기능은 InvocationHanlder를 구현한 오브젝트에 담아서 전달한다. InvocationHanlder에는 invoke 메소드를 정의하기 때문에, 하나의 InvocationHanlder를 받음으로써 리플랙션으로 Target 오브젝트에 구현되어있는 여러 종류의 메소드를 대신 실행할 수 있는 것이다. 따라서 InvocationHanlder를 구현하는 구현체를 만듦으로써 부가기능을 적용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class UppercaseHandler implements InvocationHanlder {
  Hello target; //실제 사용할 타깃. 인터페이스로 정의한다.

  public UppercaseHandler(Hello target) {
    this.target = target;
  }

  //InvocationHanlder에 정의되어있는 메소드. 부가기능을 직접 구현하는 부분으로 사용된다.
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String ret = (String)method.invoke(target, args); //타깃으로 핵심기능 위임.
    return ret.toUpperCase(); // 부가기능 제공
  }
}



출처 : 토비의 스프링 06. AOP

이미지 출처

  • http://powermmo.com/tech/why-to-buy-a-proxy-server/
  • https://dzone.com/articles/design-patterns-proxy