글 검색

공개된 글의 제목과 본문을 검색합니다.

    닫기 Esc

    프록시 패턴(Proxy Pattern)#

    프록시 패턴은 특정 객체로의 접근을 제어하는 대리인(특종 객체를 대변하는 객체)을 제공합니다.

    • 프록시 패턴을 사용하면 원격 객체라던가 생성하기 힘든 객체, 보안이 중요한 객체와 같은 다른 객체로의 접근을 제어하는 대리인 객체를 만들 수 있다.
    • 프록시에서 접근을 제어하는 방법
      • 원격 프록시를 써서 원격 객체로의 접근을 제어할 수 있음
      • 가상 프록시를 써서 생성하기 힘든 자원으로의 접근을 제어할 수 있음
      • 보호 프록시를 써서 접근 권한이 필요한 자원의 접근을 제어할 수 있음
    • 호출을 중간에서 가로챈다는게 중요하다.

    원격 프록시#

    • 원격 프록시는 원격 객체의 로컬 대변자 역할을 하게 됩니다.
    • 원격 객체란 다른 자바 가상머신의 힙에서 살고있는 객체를 뜻합니다.
    • 로컬 대변자를 호출하면 다른 원격 객체에게 그 메소드를 호출을 전달해주는 객체를 뜻합니다.
    • 결과적으로 클라이언트는 로컬 객체를 사용하는것처럼 행동할 수 있습니다.

    원격 메소드의 호출 과정#

    1. 클라이언트 객체에서 특정 메소드를 사용
    2. 메소드 명과 인자 값 등을 직렬화해서 네트워크로 원격 객체에 전달
    3. 원격 객체는 로직을 수행
    4. 결과를 다시 직렬화하여 프록시 객체에게 전달
    5. 프록시 객체는 메소드가 완료된 것처럼 작동

    가상 프록시#

    • 객체 생성하는데 많은 비뵹이 드는 객체를 대신합니다.

    가상 프록시의 작동 과정#

    이미지를 불러오는 객체를 기준으로 했을 때

    1. 이미지를 불러오는 객체를 가상 프록시로 만들어 이미지를 가져오는 메소드를 실행
      1. 가상 프록시는 화면에 이미지를 가져오는 중이라는 메세지를 나타나게 함
    2. 잠시 후 이미지 로딩이 완료되고, 실제 객체가 완성됨
    3. 이미지 생성이 완료된 객체를 통해서 화면에 이미지를 노출 시킴

    원격 프록시와 가상 프록시 비교#

    • 원격 프록시
      • 원격 프록시는 다른 JVM에 들어있는 객체의 대리인에 해당하는 로컬 객체
      • 프록시의 메소드를 호출하면 그 호출이 네트워크로 전달되어 결국 원격 객체의 메소드가 호출됨
      • 그 결과는 다시 프록시를 거쳐서 클라이언트에게 전달됨
    • 가상 프록시
      • 가상 프록시는 생성하는 데 많은 비용이 드는 객체를 대신함
      • 진짜 객체가 필요한 상황이 오기 전까지 객체의 생성을 미루는 기능을 제공
      • 객체 생성 전이나 객체 생성 도중에 객체를 대신하기도하고, 생성이 끝나면 직접 요청을 전달 하기도함

    데코레이터와 프록시의 차이점#

    • 사용 용도로 구분이 가능하다.
    • 데코레이터는 클래스에 새로운 동작을 추가하는 용도로 사용된다.
    • 프록시는 어떤 클래스로의 접근을 제어하는 용도로 사용된다.

    어댑터와 프록시의 차이점#

    • 어댑터는 다른 객체의 인터페이스를 바꿔줍니다.
    • 프록시는 동일한 인터페이스를 사용합니다.

    보호 프록시#

    • 자바의 java.lang.reflect 패키지 안에 프록시 기능이 내장되어 있다.
    • 지정한 클래스에 메소드 호출을 전달하는 프록시 클래스를 만들 수 있다.
    • 진짜 프록시 클래스는 실행 중 생성되므로 이러한 자바 기술을 동적 프록시(dynamic proxy)라고 부른다.
    • 특정 인터페이스 메소드 접근의 권한에 따라서 이용 가능 여부를 지정할 수 있다.

    만들어보기#

    java
    public interface Person {
    		String getName();
    		String getGender();
    		String getInterests();
    		int getGeekRating();
    		
    		void setName(String name);
    		void setGender(String gender);
    		void setInterests(String interests);
    		void setGeekRating(int rating); 
    }
    java
    import java.lang.reflect.*;
     
    public class OwnerInvocationHandler implements InvocationHandler { 
    		Person person;
    		
    		public OwnerInvocationHandler(Person person) {
    				this.person = person;
    		}
    		
    		public Object invoke(Object proxy, Method method, Object[] args) 
    				throws IllegalAccessException {
    		
    				try {
    						if (method.getName().startsWith("get")) {
    								return method.invoke(person, args);
    						} else if (method.getName().equals("setGeekRating")) {
    								throw new IllegalAccessException();
    						} else if (method.getName().startsWith("set")) {
    								return method.invoke(person, args);
    						} 
    				} catch (InvocationTargetException e) {
    						e.printStackTrace();
    				} 
    				return null;
    		}
    }
    java
    Person getOwnerProxy(Person person) {
    		return (Person) Proxy.newProxyInstance( 
    				person.getClass().getClassLoader(),
    				person.getClass().getInterfaces(),
    				new OwnerInvocationHandler(person));
    }
    전체 글 둘러보기