Proxy는 무엇인가 개념부터 장단점까지

KUN·2025년 6월 9일

목적

Proxy 라는 키워드를 여러 번 접했는데, 지금까지는 깊게 이해하지 못하고 넘어갔다.
그래서 이번 기회에 Proxy무엇인지, 어떤 상황에서 쓰이는지 조사해보고 정리해보려 한다.

목표

  • Proxy 정의

  • Proxy의 어원

  • Proxy를 사용하는 이유

  • Proxy의 종류 (정적 Proxy vs 동적 Proxy)

  • Proxy가 사용되는 사례 (JPA, AOP)

  • Proxy의 장단점 및 사용 시 주의사항


Proxy 무엇인가

어원

정의 - Wikipedia

프록시는 클라이언트가 호출하여 실제 서비스 객체에 접근하기 위한 래퍼 또는 에이전트 객체이다.
프록시의 사용은 단순히 실제 객체로 요청을 전달하는 것일 수도 있고, 
추가적인 로직을 제공하는 것일 수도 있다.

Proxy는 다른 객체에 대한 접근을 제어하거나 대신 처리하는 객체를 말한다.
즉, 클라이언트는 Proxy를 통해서 실제 객체를 직접 접근하지 않고,
Proxy가 중간에서 대신 역할을 수행한다.

정리

Proxy는 실제 객체 대신 중간에서 요청을 전달하거나 추가 기능을 수행하는 대리 객체이다.

아직 이해가 안되었다면 아래와 같이 생각하자.

직접 책 찾으러 서고에 가지 않고, 사서(Proxy) 가 대신 찾아서 가져다준다.


필요성

Medium - Proxy

Access Control(접근 제어)
프록시는 실제 객체에 대한 접근을 제어할 수 있다.
예를 들어, 메서드 호출이 진행되기 전에 사용자 권한이나 액세스 토큰을 확인할 수 있다.

		도서관에 어떤 책들은 [열람 제한] 이 걸려 있다.
		사서(Proxy)가 회원 등급이나 열람 허가 여부를 확인한 뒤에만 책을 꺼내준다.
		즉, 아무나 직접 책 접근 불가하며 사서가 확인 후 허용한다.

Lazy Initialization(지연 초기화)
프록시는 비용이 많이 드는 객체의 생성 또는 로딩을, 해당 객체가 실제로 필요할 때까지 지연할 수 있다.

		도서관에서 희귀본 책은 평소에 서고에 꺼내놓지 않는다.
		사서(Proxy)는 "이 책을 보고 싶다"는 요청이 들어왔을 때에만 별도의 보관소에서 책을 꺼내온다.
		필요할 때만 책을 준비함으로써 공간과 관리 비용을 절약할 수 있다.

Additional Functionality(추가 기능)
프록시는 실제 객체로 가는 과정에서 추가적인 동작을 넣을 수 있다.
예를 들어, 결과를 캐싱하거나, 호출 로그를 남겨 감사를 위한 기록을 할 수 있다.

		사서(Proxy)는 책을 꺼내줄 때, "누가 언제 어떤 책을 열람했는지" 기록을 남긴다.
		또는 "이 책은 대출 금지이며 열람만 가능하다"와 같은 추가 규칙을 적용하기도 한다.
		즉, 단순히 책을 전달하는 것 외에 중간에서 부가적인 기능을 수행한다.

Interface Transparency(인터페이스 투명성)
프록시는 실제 객체와 동일한 인터페이스를 구현하기 때문에,
클라이언트는 코드 변경 없이 프록시를 사용할 수 있다.
프록시를 사용하는 것은 실제 객체를 사용하는 것과 동일한 느낌으로 동작한다.

		도서관 이용자는 언제나 "책을 주세요"라고 사서에게 요청한다.
		책의 종류나 위치에 상관없이 이용자는 동일한 방식으로 요청할 수 있으며, 사서가 알아서 처리한다.
		따라서 이용자 입장에서는 Proxy(사서)가 존재하더라도 실제 책을 이용하는 방식에는 차이가 없다.

정적과 동적

정적 Proxy

정적 Proxy 는 프록시 클래스를 개발자가 직접 만든 경우를 의미한다.
즉, 실제 서비스 객체를 감싸는 Proxy 클래스를 코드로 미리 작성하는 방식이다.
이 경우 Proxy 클래스는 컴파일 시점에 이미 존재하며, 개발자가 프록시가 어떤 일을 할지 명시적으로 작성하게 된다.

EX ) 개발자가 직접 MemberServiceProxy 클래스를 만들어서 MemberService 를 감싸고, 로깅이나 트랜잭션 처리를 추가하는 경우가 이에 해당한다.

동적 Proxy

동적 Proxy 는 런타임(프로그램 실행 중)에 프록시 객체가 자동으로 생성되는 경우를 의미한다.
개발자가 직접 Proxy 클래스를 만들지 않아도, 프레임워크가 Proxy 객체를 동적으로 만들어준다.
이때 프록시는 인터페이스 기반일 수도 있고, 클래스 기반일 수도 있다.

EX ) Spring에서 @Transactional, @Async, @Cacheable 같은 기능을 사용하면, 개발자는 별도의 Proxy 코드를 만들지 않아도 된다.

정리

정적 Proxy는 프록시 클래스를 개발자가 직접 작성하는 것,
동적 Proxy는 실행 시점에 프레임워크가 자동으로 프록시를 만들어주는 것이다.


사용 사례

JPA에서의 Proxy

JPA에서는 데이터베이스에서 엔티티(객체)를 가져올 때,
처음부터 데이터를 다 가져오는 것이 아니라 Proxy 객체를 먼저 만들어서 반환할 수 있다.

예를 들어, 주문(Order)을 조회할 때 주문한 회원(Member)의 정보까지 꼭 지금 당장 필요한 건 아닐 수 있다.
이 경우 JPA는 Member 대신 Proxy 객체를 넣어준다.
→ 이후 member.getName() 처럼 실제 데이터가 필요할 때, 그제서야 DB 쿼리를 날린다.

정리
처음부터 불필요한 쿼리를 날리지 않고,
필요할 때만 데이터를 조회하기 위해 Proxy를 사용한다.

AOP에서의 Proxy

스프링에서 @Transactional, @Async, @Cacheable 같은 기능은
프록시가 중간에 끼어서 메서드 실행을 가로챈 후,
트랜잭션 시작, 비동기 처리, 캐시 확인 같은 작업을 해준다.

예를 들어,

@Transactional
public void order()

라고 적으면,
실제로는 Proxyorder() 호출을 가로채서
→ 트랜잭션 시작 → 실제 order() 실행 → 트랜잭션 커밋
이런 흐름으로 실행된다.

정리
메서드 실행 전후에 추가 기능(트랜잭션, 로그 등)을 자동으로 넣기 위해 Proxy를 사용한다.
개발자는 별도로 코드를 만들 필요가 없다.


장단점 및 주의사항

Proxy - refactoring.guru

장점

  • 클라이언트가 모르는 사이에 서비스 객체를 제어할 수 있다.
  • 클라이언트가 서비스 객체의 생명주기에 관심 없을 때, 그 생명주기를 관리할 수 있다.
  • 서비스 객체가 아직 준비되지 않았거나 사용 불가능한 경우에도 프록시는 동작할 수 있다.
  • 개방/폐쇄 원칙(Open/Closed Principle)
    서비스나 클라이언트를 변경하지 않고도 새로운 프록시를 도입할 수 있다.

단점

  • 많은 새로운 클래스를 도입해야 하므로 코드가 더 복잡해질 수 있다.
  • 서비스로부터의 응답이 지연될 수 있다.

배운 점

  • Proxy(프록시)는 실제 객체 대신 중간에서 요청을 제어하거나 기능을 추가하는 객체라는 것을 배웠다.

  • 정적 Proxy는 개발자가 직접 만들고, 동적 Proxy는 실행 시 자동으로 만들어진다는 차이가 있다.

  • JPA에서는 Proxy를 통해 지연 로딩을 구현하고, 스프링 AOP에서는 Proxy를 사용해 트랜잭션, 로깅 등의 기능을 쉽게 추가할 수 있다는 점이 인상 깊었다.


Daily Refactoring Guru

Proxy - refactoring.guru

왜 객체에 대한 접근을 제어해야 할까요?
예를 들어, 시스템 자원을 많이 소모하는 아주 큰 객체가 있다고 가정해봅시다.
이 객체는 가끔 필요하지만, 항상 필요한 것은 아닙니다.

								Proxy 패턴이 해결하는 문제
							데이터베이스 쿼리는 매우 느릴 수 있습니다.

이를 해결하기 위해 지연 초기화(lazy initialization) 를 구현할 수 있습니다.
즉, 해당 객체가 실제로 필요할 때만 객체를 생성하는 방식입니다.
하지만 이 경우 객체를 사용하는 모든 클라이언트가 초기화를 위한 지연 코드를 따로 작성해야 합니다.
그 결과 중복 코드가 많이 발생할 수 있습니다.
profile
배우노라, 실험하노라, 기록하노라

0개의 댓글