스택큐힙리스트

Proxy 패턴: ‘대리’로 구현하는 로깅·보안·캐싱 마법 본문

개발

Proxy 패턴: ‘대리’로 구현하는 로깅·보안·캐싱 마법

스택큐힙리스트 2025. 7. 21. 19:17
반응형

1️⃣ Proxy 패턴, 한마디 정의

‘Proxy(프록시)’는 대리인이라는 뜻 그대로, 원본 객체 앞에 서서 호출을 가로채거나 대신 처리하는 구조(Structural) 패턴이다. 클라이언트는 Proxy를 통해서만 원본에 접근하므로, 접근 제어·로깅·캐싱·지연 로딩 등을 가볍게 끼워 넣을 수 있다.


2️⃣ 언제 써먹으면 좋은가?

  • 로깅·메트릭 수집 – 모든 서비스 메서드 앞뒤에 실행 시간을 재려 할 때
  • 보안·권한 체크 – 호출자 정보 확인 후 원본 메서드 실행 허용 여부 결정
  • 캐싱 – 동일 파라미터로 반복 호출 시 결과를 캐시해 DB 부하 절감
  • 가상 프록시(Virtual) – 고비용 객체를 ‘필요할 때만’ 초기화해 메모리 세이브
    이처럼 “추가 책임을 원본 코드 수정 없이 붙이고 싶다”는 요구가 나오면 Proxy가 정답이다.

3️⃣ Proxy가 Adapter·Facade와 다른 점

  • Adapter : 호환되지 않는 인터페이스 변환이 목적
  • Facade : 복잡한 서브시스템 단일화가 목적
  • Proxy : 원본 접근 제어·확장이 목적 (인터페이스·서브시스템은 그대로)
    즉, Proxy는 “원본 그대로 두고 통로만 장악”하는 전략이다.

4️⃣ Spring Boot 예시 – 동적 로깅 Proxy

public interface OrderService {
    void placeOrder(String id);
}

/* 실제 기능 */
@Service
@RequiredArgsConstructor
public class RealOrderService implements OrderService {
    private final OrderRepository repo;
    public void placeOrder(String id) { repo.save(new Order(id)); }
}

/* 프록시 – 런타임 생성 */
@Component
public class LogProxyConfig {

    @Bean
    public OrderService orderService(RealOrderService target) {
        return (OrderService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            new Class<?>[]{OrderService.class},
            (proxy, method, args) -> {
                long start = System.currentTimeMillis();
                try {
                    return method.invoke(target, args);   // 원본 위임
                } finally {
                    System.out.printf("%s took %d ms%n",
                        method.getName(), System.currentTimeMillis() - start);
                }
            });
    }
}

Proxy.newProxyInstance가 런타임에 인터페이스 구현체를 생성해 RealOrderService를 래핑한다. 컨트롤러·서비스는 빈 교체만으로 자동 로깅 기능을 얻게 된다.


5️⃣ 구현 꿀팁 🔥

  1. Immutable 파라미터 주입 – Proxy 내부에서 상태를 변경하면 원본과 충돌 위험, 불변 객체를 권장.
  2. 구현체 선택 기준
    • JDK 동적 프록시 : 인터페이스 기반, 가볍지만 클래스가 필요
    • CGLIB·ByteBuddy : 상속 기반, 인터페이스 없어도 OK (Spring AOP 기본)
  3. 체인 폭주 주의 – Proxy를 여러 겹 감싸면 호출 스택이 길어지므로, 공통 관심사는 Spring AOP·필터·인터셉터로 분산.
  4. 테스트 더블 – 단위 테스트에선 Proxy 대신 RealOrderService를 주입해 로깅 시간 손실을 제거하자.

한 줄 요약

Proxy 패턴은 “코드를 고치지 않고 기능을 ‘대리’로 추가하는 만능 플러그인 슬롯”이다.

반응형
Comments