본문 바로가기

카테고리 없음

Proxy Pattern 프록시 패턴

프록시 패턴이란?


Proxy는 '대리'라는 뜻으로 무언가를 대신 처리한다는 의미이다.

어떠한 객체를 사용하고 싶을 때 객체를 직접적으로 참조하는 것이 아닌, 해당 객체를 대리할 수 있는 객체를 통해 대상 객체에 접근하는 방식을 사용한다.

원격 객체, 생성하기 힘든 객체, 보안이 중요한 객체와 같은 다른 객체로의 접근을 제어하는 대리 객체를 생성할 수 있다.

인터페이스를 통해 실행시킬 클래스에 대한 객체가 들어갈 자리에 대리 객체를 대신 투입한다.

(클라이언트 쪽에서 실제 실행시킬 클래스에 대한 객체를 통해 메소드를 호출하고 반환 값을 받는지, 대리 객체를 통해 메소드를 호출하고 반환 값을 받는지 모르게 처리하는 방법)

 

프록시의 특징

  • 인터페이스를 통해 실제 서비스와 같은 이름의 메소드를 구현한다.
  • 실제 서비스에 대한 참조 변수를 갖는다.
  • 실제 서비스와 같은 이름을 가진 메소드를 호출하고 그 값을 클라이언트에게 돌려준다.
  • 실제 서비스를 수행하는 객체 대신 대리 객체를 사용하여 로직의 흐름을 제어한다.
  • 원격 프록시를 써서 원격 객체로의 접근을 제어할 수 있다.
  • 가상 프록시를 써서 생성하기 힘든 자원으로의 접근을 제어할 수 있다.
  • 보호 프록시를 써서 접근 권한이 필요한 자원으로의 접근을 제어할 수 있다.

 

프록시의 장점

  • 타겟 객체에 대한 레퍼런스가 미리 필요할 경우, 객체를 생성해서 넘겨주지 않고 프록시를 먼저 넘겨준 후 프록시의 메소드를 통해 실제로 사용될 때 타겟 객체를 생성할 수 있다. (가상 프록시)
  • 특정 상황에서 접근권한을 제어할 수 있다. 특정 조건이 만족되면 타겟의 핵심 로직을 호출하기 전에 예외를 던져 접근을 불가능하게 만들 수 있다. (보호 프록시)
  • 캐싱이 가능하여 요청 받은 데이터가 메모리에 존재할 경우, 프록시는 타겟으로 요청을 보내지 않고, 기존 응답의 데이터를 클라이언트에게 전달한다. (원격 프록시)
    • 원격 프록시는 클라이언트와 서버 사이에 대리로 통신을 수행하는 것으로 해당 기능을 하는 서버를 프록시 서버라고 한다.
    • 프록시 서버 캐시에 필요한 데이터가 있다면 실제 서버까지 요청을 전달하지 않아도 데이터를 빠르게 가져올 수 있다.
    • 캐싱 프록시 (https://www.ibm.com/docs/ko/was-nd/9.0.5?topic=caching-overview-proxy-server)
      • 프록시 서버가 하나 이상의 클라이언트 시스템의 요청 및 데이터를 저장할 수 있는 인터넷 / 네트워크 캐싱 기술 유형.
      • 주로 웹 사이트 엑세스 시간을 개선하고 데이터 다운로드를 최소화하며 대역폭 사용량을 줄이기 위해 사용된다.
      • 프록시 서버가 자주 사용하는 웹 사이트 및 인터넷 기반 리소스에 대한 데이터를 분석 및 저장할 때 작동된다.
      • 프록시 캐시에 로컬로 저장된 데이터와 일치하는 웹 페이지 또는 리소스에 대한 클라이언트 요청이 이루어지면 프록시 서버는 즉시 데이터를 검색하여 전달한다.

 

프록시의 단점

  • 객체를 생성할 때 한 단계를 거치게 되므로, 객체 생성이 빈번하게 일어날 경우 성능이 저하될 수 있다.
  • 로직이 난해해져 가독성이 떨어질 수 있다.

 

프록시 패턴의 구조 (https://esoongan.tistory.com/180)

Subject

Proxy와 RealSubject 모두 Subject 인터페이스를 구현한다. (어떤 클라이언트에서든 프록시를 주제와 똑같은 식으로 다룰 수 있다.)

 

RealSubject

RealSubject는 진짜 작업을 대부분 처리하는 객체이다.

 

Proxy

진짜 작업을 처리하는 객체의 레퍼런스가 들어있다. RealSubject의 객체가 필요하면 해당 레퍼런스를 사용해 요청을 전달한다. (RealSubject 객체로의 접근을 제어한다.)

 

 

프록시 패턴의 대표 3가지


원격 프록시(Remote Proxy)

  • 다른 JVM에 들어있는 객체의 대리인에 해당하는 로컬 객체
  • 프록시의 메소드를 호출하면 네트워크로 전달되어 원격 객체의 메소드를 호출한다.
  • 결과는 다시 프록시를 거쳐 클라이언트에게 전달된다.

 

가상 프록시(Virtual Proxy)

  • 생성하는데 많은 비용이 드는 객체를 대신한다.
  • 진짜 객체가 필요한 상황이 오기 전까지 객체의 생성을 미루는 기능을 제공한다.
  • 객체 생성 전이나 생성 도중에 일부 요청을 직접 처리할 수 있다.
  • 진짜 객체의 생성이 완료된 상태라면 직접 요청을 전달한다.

 

보호 프록시(Protection Proxy)

  • 객체에 대한 접근 권한을 제어하거나 객체마다 접근 권한을 달리하고 싶을 경우 사용한다.
  • 프록시 클래스에서 클라이언트가 주체 클래스에 대한 접근을 허용할지 말지 결정하도록 할 수 있다.
  • (사용자에 따른 권한 부여)

 

 

사용 예시


Subject 인터페이스의 request()를 호출하면 구현 클래스인 SubjectImpl의 request()가 프록시를 통해 호출된다.

 

ISubject Interface

public interface ISubject {

	public String request();
}

 

SubjectImpl Class

public class SubjectImpl implements ISubject {

	@Override
	public String request() {
		return "response";
	}
}

 

Proxy Class

public class Proxy implements ISubject {

	private final SubjectImpl subject = new SubjectImpl();
	
	@Override
	public String request() {
		// 실제 메소드 호출
		return subject.request();
	}
}

 

Main Class

public class Main {

	public static void main(String[] args) {
		
		ISubject subject = new Proxy();
		System.out.println(subject.request());
	}
}

 

프록시를 통해 구현 클래스에 직접 접근하지 않고 우회하여 흐름을 제어하는 모습을 볼 수 있다.

(프록시 패턴의 설계 구조)

 

 

가상 프록시 사용 예제 ( 헤드 퍼스트 디자인 패턴 예제 )

https://github.com/yyh7750/CS-/tree/master/CS/src/proxy/virtual

 

보호 프록시 사용 예제 ( 헤드 퍼스트 디자인 패턴 예제 )

https://github.com/yyh7750/CS-/tree/master/CS/src/proxy/protection

  • java.lang.reflect 패키지 안에 프록시 기능이 내장되어 있다.
  • 위 패키지를 사용하면 즉석에서 하나 이상의 인터페이스를 구현하고, 지정한 클래스에 메소드 호출을 전달하는 프록시 클래스를 만들 수 있다.
  • 진짜 프록시 클래스는 실행 중에 생성되는데 이러한 자바 기술을 동적 프록시(dynamic proxy)라고 부른다.
  • 해당 예제는 동적 프록시를 활용하여 보호 프록시를 구현한다.
    • 자바에서 Proxy 클래스를 생성해 주므로 Proxy 클래스에게 무슨 일을 해야 하는지 알려줄 방법이 필요하다.
    • 필요한 코드를 직접 구현하는 것이 아니기 때문에 프록시 클래스에 코드를 구현할 수 없다.
    • 때문에, 프록시에 호출되는 모든 메소드에 응답하는 Handler를 만들어 준다.

 

 

※ 스프링 AOP에서의 프록시 사용

https://mangkyu.tistory.com/175 참고