Spring adv 04 - Proxy Pattern
Proxy
클라이언트가 요청한 결과를 서버에 직접 요청하는 것이 아니라 어떤 대리자를 통해서 대신 간접적으로 서버에 요청할 수 있다. 예를 들어서 내가 직접 마트에서 장을 볼 수도 있지만, 누군가에게 대신 장을 봐달라고 부탁할 수도 있다. 여기서 대신 장을 보는 대리자를 영어로 프록시(Proxy)라 한다.
예시
재미있는 점은 직접 호출과 다르게 간접 호출을 하면 대리자가 중간에서 여러가지 일을 할 수 있다는 점이다.
- 엄마에게 라면을 사달라고 부탁 했는데, 엄마는 그 라면은 이미 집에 있다고 할 수도 있다. 그러면 기대한 것 보다 더 빨리 라면을 먹을 수 있다. (접근 제어, 캐싱)
- 아버지께 자동차 주유를 부탁했는데, 아버지가 주유 뿐만 아니라 세차까지 하고 왔다. 클라이언트가 기대한 것 외에 세차라는 부가 기능까지 얻게 되었다. (부가 기능 추가)
- 대리자가 또 다른 대리자를 부를 수도 있다.
- 예를 들어서 내가 동생에게 라면을 사달라고 했는데, 동생은 또 다른 누군가에게 라면을 사달라고 다시 요청할 수도 있다.
- 중요한 점은 클라이언트는 대리자를 통해서 요청했기 때문에 그 이후 과정은 모른다는 점이다. 동생을 통해서 라면이 나에게 도착하기만 하면 된다. (프록시 체인)
프록시의 주요 기능
프록시를 통해서 할 수 있는 일은 크게 2가지로 구분할 수 있다.
- 접근 제어
- 권한에 따른 접근 차단
- 캐싱
- 지연 로딩
- 부가 기능 추가
원래 서버가 제공하는 기능에 더해서 부가 기능을 수행한다. 요청 값이나, 응답 값을 중간에 변형한다. 실행 시간을 측정해서 추가 로그를 남긴다. 프록시 객체가 중간에 있으면 크게 접근 제어와 부가 기능 추가를 수행할 수 있다.
- 프록시 패턴: 접근 제어가 목적
- 데코레이터 패턴: 새로운 기능 추가가 목적
둘다 프록시를 사용하지만, 의도가 다르다는 점이 핵심이다. 용어가 프록시 패턴이라고 해서 이 패턴만 프록시를 사용하는 것은 아니다. 데코레이터 패턴도 프록시를 사용한다.
이와 같은 객체 의존관계를 코드로 구현해보자
앞서 설명한 것 처럼 프록시도 실제 객체와 그 모양이 같아야 하기 때문에 Subject 인터페이스를 구현해야 한다.
- private Subject target: 클라이언트가 프록시를 호출하면 프록시가 최종적으로 실제 객체를 호출해야 한다.
- 따라서 내부에 실제 객체의 참조를 가지고 있어야 한다. 이렇게 프록시가 호출하는 대상을
target이라 한다. - operation(): 구현한 코드를 보면
cacheValue에 값이 없으면 실제 객체(target)를 호출해서 값을 구한다. - 그리고 구한 값을
cacheValue에 저장하고 반환한다. 만약cacheValue에 값이 있으면 실제 객체를 전혀 호출하지 않고, 캐시 값을 그대로 반환한다. - 따라서 처음 조회 이후에는 캐시(
cacheValue)에서 매우 빠르게 데이터를 조회할 수 있다.
데이터가 엄청 빠르게 조회되는 것을 확인할 수 있다. 처음에는 cacheValue에 데이터가 없기 때문에 실제 데이터를 담아두고 그 다음에 조회할 때는 cacheValue에서 데이터를 매우 빠르게 조회하는 것이 프록시의 역할이다. 결과적으로 realSubject 와 cacheProxy 를 생성하고 둘을 연결한다.cacheProxy 가 realSubject를 참조하는 런타임 객체 의존관계가 완성된다. 그리고 마지막으로 client 에 realSubject 가 아cacheProxy 를 주입한다. 이 과정을 통해서 client -> cacheProxy -> realSubject 런타임 객체 의존 관계가 완성된다.
Reference
김영한님의 스프링 핵심 원리
나의 뇌