Java/Design Pattern

[헤드퍼스트 디자인 패턴] 11. 프록시 패턴

noahkim_ 2024. 12. 18. 22:42

에릭 프리먼 님의 "헤드퍼스트 디자인 패턴" 책을 정리한 포스팅 입니다

 

1. 프록시 패턴

  • 다른 객체에 대한 접근을 제어하기 위해 그 객체의 대리인을 사용하는 디자인패턴
  • 원래 객체에 직접 접근하는 것이 아닌, 프록시를 통해 간접적으로 접근하도록 함

 

구성 요소

구성 요소 설명
Subject(인터페이스)
원래 객체와 프록시가 공통으로 구현하는 인터페이스
RealSubject
실제 작업을 수행하는 객체
Proxy
RealSubject에 대한 접근을 제어하는 대리 객체

 

사용처

목적 설명
접근 제어
보안, 인증, 권한 제어를 위해 직접 접근 대신 프록시에서 제어함
지연 초기화
무거운 객체의 생성/로딩을 실제 필요 시점까지 미루기 위해 사용
원격 호출
네트워크나 다른 JVM에 있는 객체와 통신하기 위한 로컬 대리 객체 제공
부가 기능 추가
성능 측정, 캐싱, 로깅 등의 기능을 원본 객체에 영향을 주지 않고 프록시에서 처리함

 

2. 예제: Dating

Person

  • 자신의 정보를 직접 수정하는 것을 막아야 함
더보기
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);
}

 

Proxy

  • 프록시의 행동을 구현
더보기

InvocationHander (java.lang.reflect)

public interface InvocationHandler { 	
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;        
}
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().equals("setGeekRating") throw new IllegalAccessException();
            
            if (method.getName().startsWith("get") || method.getName().startsWith("set")) return method.invoke(person, args);            
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        
        return null;
    }
}
  • 자신 핸들러
  • 클라이언트용 핸들러

 

동적 프록시 생성

더보기
Person getOwnerProxy(Person person) {
    return (Person) Proxy.newProxyInstance(
    	person.getClass().getClassLoader(),
        person.getClass().getInterfaces(),
        new OwnerInvocationHandler(person));
}

 

3. 원격 프록시

  • 원격 객체의 로컬 대변자
  • 어떤 메서드를 호출하면, 다른 원격 객체에게 그 메서드 호출을 전달해 주는 객체
항목 설명
목적
클라이언트가 로컬 객체처럼 사용할 수 있게 하면서, 내부적으로는 원격 호출 처리
클라이언트 역할
원격 객체가 로컬에 있는 것처럼 메서드를 호출
프록시 역할
저수준 작업 담당 (네트워크 연결, 요청 전송, 응답 수신, 예외 처리 등)
원격 객체 역할
실질적인 비즈니스 로직 수행 (서버 측 객체)

 

4. 예시: RMI

  • 자바의 원격 메서드 호출 기능
  • 클라이언트와 서버 간 통신을 자동화
구성 요소 설명 역할
Stub 클라이언트 측 보조 객체
원격 객체를 로컬처럼 호출하게 해줌
클라이언트 → 서버 호출 프록시
Skeleton 서버 측 보조 객체
요청을 실제 객체에 전달하고 결과를 반환함
요청 디코딩 → 실제 객체 실행
Remote Object 실제 비즈니스 로직을 수행하는 서버 측 객체
원격으로 호출되는 진짜 대상