디자인패턴

AOP와 프록시 패턴의 관계

국자집사 2025. 1. 24. 16:06

[ 목차 ]

     

    소프트웨어 개발에서 유지보수성과 확장성을 높이기 위해 AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)프록시 패턴(Proxy Pattern)이 자주 사용된다. 두 개념은 공통된 목표를 가지지만 적용 방식과 활용 범위에서 차이가 있다. 이 글에서는 AOP의 개념과 프록시 패턴과의 관계, 그리고 Spring 프레임워크에서의 적용 방식을 살펴보겠다.

     

    1. AOP란?

    AOP(관점 지향 프로그래밍)는 핵심 로직과 부가적인 관심사를 분리하여 모듈화하는 프로그래밍 패러다임입니다. 이를 통해 중복 코드를 줄이고 코드의 가독성을 높일 수 있다.

    AOP의 필요성

    • 중복 코드 제거: 로깅, 트랜잭션, 보안 검증과 같은 기능을 별도의 모듈로 분리.
    • 유지보수성 향상: 핵심 로직과 부가 기능을 분리하여 코드 변경이 용이.
    • 관심사의 분리: 기능을 독립적으로 관리하여 코드의 명확성 증가.

     

    AOP의 주요 개념

    1. Aspect(관점): 부가적인 기능(로깅, 트랜잭션)을 모듈화한 단위.
    2. Advice(조언): 언제(시점)에 무엇을 실행할지 정의.
    3. Join Point(연결 지점): Advice가 실행될 수 있는 지점(메서드 호출, 객체 생성 등).
    4. Pointcut(포인트컷): Advice가 적용될 구체적인 위치를 지정하는 표현식.
    5. Weaving(위빙): 코드 실행 시점에 Advice를 적용하는 과정.

     

    AOP에 대해서 더 알고싶다면 ↓ ↓ ↓ ↓

     

    POJO(IoC/DI, AOP)

    [ 목차 ]스프링 프레임워크란?스프링 프레임워크(Spring Framework)는 엔터프라이즈 애플리케이션 개발을 간소화하기 위한 오픈소스 프레임워크다. 경량화와 유연성을 목표로 설계되었으며, 다음과

    rnrwk0502.tistory.com

     


    2. 프록시 패턴과 AOP의 관계

    프록시 패턴과 AOP는 모두 기능을 분리하고 재사용성을 높이는 목적을 가지지만, 적용 방식과 범위에서 차이가 있다.

     

    공통점

    • 관심사 분리: 핵심 로직과 부가 기능을 분리하여 코드의 복잡성을 줄임.
    • 객체 접근 제어: 클라이언트가 직접 대상 객체에 접근하지 않고 프록시를 통해 제어.
    • 코드 재사용: 중복되는 로직을 한 곳에서 관리하여 유지보수성을 향상.
    • 캡슐화: AOP와 프록시 패턴 모두 부가 기능을 캡슐화하여 핵심 로직과 분리.

     

    차이점

    항목 프록시패턴 AOP
    목적 객체의 접근 제어 및 기능 추가 횡단 관심사를 분리하여 관리
    적용 범위 특정 객체 및 메서드 애플리케이션 전반
    구현 방식 수동 구현 (Proxy 클래스) 선언적 방식 (어노테이션, XML)
    사용 사례 로깅, 접근 제어 로깅, 트랜잭션, 보안
    위빙 시점 런타임 적용 컴파일 또는 런타임 적용

     

     

    프록시 패턴과 AOP의 상호 보완

    AOP는 내부적으로 프록시 패턴을 활용하여 핵심 로직과 부가 기능을 분리한다.

    예를 들어, Spring AOP는 프록시 패턴을 사용하여 런타임에 동적으로 객체의 기능을 확장한다. 이처럼 AOP는 프록시 패턴을 기반으로 하여 좀 더 선언적이고 유연한 방식을 제공한다.

     

    예시:

    • 프록시 패턴을 사용하면 특정 객체에 대한 접근 제어나 로깅, 캐싱을 수동으로 구현해야 하지만,
    • AOP는 선언적으로 Pointcut과 Advice를 설정하여 더욱 간편하게 적용할 수 있다.

     

    프록시 패턴과 AOP의 선택 기준

    사용 목적 선택해야 할 기술
    특정 객체의 보안 및 접근 제어 프록시 패턴
    애플리케이션 전반의 로깅, 트랜잭션 AOP
    런타임 제어 및 동적 확장 프록시 패턴 및 AOP 조합

     

    AOP는 주로 횡단 관심사(Cross-cutting concerns) 해결에 초점을 맞추며, 애플리케이션의 다양한 부분에 적용할 수 있는 반면, 프록시 패턴은 특정 객체에 초점을 맞춘 접근 제어 및 성능 최적화에 적합하다.

     

     


    3. 프록시 패턴의 단점 해결: 다이내믹 프록시

    정적 프록시 패턴은 객체별로 개별 프록시 클래스를 생성해야 하기 때문에 유지보수가 어렵고 코드 중복이 발생할 수 있다. 이러한 문제를 해결하기 위해 다이내믹 프록시(Dynamic Proxy)가 도입되었다.

    다이내믹 프록시란?

    다이내믹 프록시는 런타임에 프록시 객체를 동적으로 생성하여 메서드 호출을 가로채고 추가적인 동작(로깅, 보안, 트랜잭션 관리 등)을 수행할 수 있도록 하는 기술이다. 이를 통해 코드 변경 없이 부가 기능을 적용할 수 있으며, 유연하고 확장성 있는 설계를 가능하게 한다.

     

    다이내믹 프록시의 특징

    • 유연성: 런타임에 프록시 객체를 동적으로 생성할 수 있어 코드 변경 없이 다양한 기능 추가 가능.
    • 코드 재사용성: 보일러플레이트 코드를 줄이고 유지보수를 용이하게 함.
    • 적용성: JDK 동적 프록시와 CGLIB 프록시 두 가지 방식으로 적용 가능.

     

    다이내믹 프록시의 분류 및 Spring 적용 방식

    다이내믹 프록시는 인터페이스의 존재 여부에 따라 JDK 프록시CGLIB 프록시로 분류된다.

    JDK 동적 프록시 (인터페이스 기반)

    • java.lang.reflect.ProxyInvocationHandler를 활용하여 인터페이스를 기반으로 프록시 생성.
    • 메서드 호출을 가로채 특정 로직(로깅, 트랜잭션 등)을 삽입 가능.
    • 단점: 인터페이스가 반드시 필요함.

    예제 코드:

    interface Service {
        void perform();
    }
    
    class RealService implements Service {
        public void perform() {
            System.out.println("실제 서비스 수행");
        }
    }
    
    class ServiceProxy implements InvocationHandler {
        private final Object target;
        public ServiceProxy(Object target) {
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("로깅: 수행 전");
            Object result = method.invoke(target, args);
            System.out.println("로깅: 수행 후");
            return result;
        }
    }

     

     

    CGLIB 프록시 (클래스 기반)

    • 바이트코드 조작을 통해 실제 클래스를 상속하여 프록시 생성.
    • 메서드 호출을 가로채 다양한 로직 추가 가능.
    • 단점: final 클래스 및 메서드는 프록시 생성 불가능.

    예제 코드:

    class RealService {
        public void perform() {
            System.out.println("실제 서비스 수행");
        }
    }
    
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(RealService.class);
    enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
        System.out.println("로깅: 수행 전");
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("로깅: 수행 후");
        return result;
    });
    RealService proxy = (RealService) enhancer.create();
    proxy.perform();

     

     

    Spring에서의 다이내믹 프록시 적용

    Spring에서는 AOP를 구현하기 위해 내부적으로 JDK 동적 프록시CGLIB 프록시를 사용한다.

    • JDK 동적 프록시: 인터페이스가 존재할 경우 적용.
    • CGLIB 프록시: 인터페이스가 없을 경우 적용.

    Spring 프록시 적용 방식 예제:

    @Aspect
    @Component
    public class LoggingAspect {
        @Before("execution(* com.example.service.*.*(..))")
        public void beforeAdvice() {
            System.out.println("메서드 실행 전 로깅");
        }
    }

    위 코드에서 @Aspect@Before 어노테이션을 통해 Spring AOP가 적용되며, 내부적으로 적절한 프록시가 생성된다.

     

     

    다이내믹 프록시의 단점 해결: 프록시 팩토리(Proxy Factory)

    다이내믹 프록시는 코드의 복잡성이 증가할 수 있으며, 다양한 프록시 요구사항을 효율적으로 처리하기 어려울 수 있다.

    이를 해결하기 위해 프록시 팩토리(Proxy Factory)가 사용된다.

     

    프록시 팩토리의 역할 :

    프록시 팩토리는JDK 동적 프록시와 CGLIB 사이의 선택을 추상화하여,

    개발자가 인터페이스의 유무에 관계없이 투명하게 프록시 객체를 생성할 수 있도록 도와주는 역할을 한다.

    즉, 프록시 팩토리는 대상 객체의 특성을 분석하고, 인터페이스가 있다면 JDK 동적 프록시를, 없다면 CGLIB를 사용하여

    프록시 객체를 자동으로 생성해준다. 

     

    이 과정은 내부적으로 처리되기 때문에, 개발자는 프록시 생성 방식의 복잡성을 신경 쓰지 않고 프록시를 사용할 수 있다.

     

    프록시 팩토리의 장점:

    • 유연성 : 프록시 생성을 위한 일관된 인터페이스 제공.
    • 재사용성 : 프록시 로직을 재사용할 수 있도록 캡슐화.
    • AOP 및 Spring과의 연동이 쉬움.

    4. AspectJ vs Spring AOP

    AOP를 적용할 때 가장 많이 사용되는 두 가지 기술은 AspectJSpring AOP이다.

    두 기술은 목적이 유사하지만 구현 방식에서 차이가 있다.

     

    AspectJ

    AspectJ는 AOP의 강력한 구현체로, 컴파일 시점(compile-time weaving) 또는 로딩 시점(load-time weaving)에 적용됩니다. 이는 바이트코드를 직접 조작하여 성능이 뛰어나며, 필드 및 생성자까지 세밀한 제어가 가능하다.

    AspectJ의 특징:

    • 애플리케이션의 모든 지점(Pointcut)에서 적용 가능 (생성자, 필드, 메서드 등)
    • 컴파일 시점에 적용되므로 런타임 성능이 우수함
    • XML 및 어노테이션 기반 설정 모두 지원

    AspectJ 적용 예시:

    @Aspect
    public class LoggingAspect {
        @Before("execution(* com.example.service.*.*(..))")
        public void beforeAdvice() {
            System.out.println("AspectJ: 메서드 실행 전 로깅");
        }
    }

     

     

    Spring AOP

    Spring AOP는 프록시 기반의 AOP로, 런타임 시 프록시 객체를 생성하여 적용됩니다. 주로 트랜잭션, 로깅 등 단순한 횡단 관심사 처리에 적합하다.

    Spring AOP의 특징:

    • 런타임 프록시 기반으로 작동 (JDK, CGLIB 사용)
    • 선언적(어노테이션) 방식 적용이 간편함
    • Spring 컨텍스트 내부 빈(Bean)에만 적용 가능

    Spring AOP 적용 예시:

    @Aspect
    @Component
    public class LoggingAspect {
        @Before("execution(* com.example.service.*.*(..))")
        public void beforeAdvice() {
            System.out.println("Spring AOP: 메서드 실행 전 로깅");
        }
    }

     

     

    비교 정리

    항목 AspectJ Spring AOP
    적용 방식 컴파일 시 코드 위빙 런타임 시 프록시 기반 위빙
    성능 빠른 실행 속도 프록시 호출로 인한 성능 저하 가능
    적용 범위 필드, 생성자, 메서드 메서드 수준 적용
    복잡성 설정이 복잡 상대적으로 간단
    코드 변경 여부 기존 코드 변경 가능 코드 변경 없이 동작

     

    - AspectJ는 애플리케이션 전반의 다양한 지점에서 AOP 적용이 가능하고, 높은 성능을 제공하지만 설정과 컴파일이 복잡할 수 있다.

    - Spring AOP는 간편한 설정과 빠른 적용이 가능하지만 메서드 수준에서만 적용되며, 일부 기능 제약이 있을 수 있다.

     

     


     

    AOP와 프록시 패턴은 코드의 유지보수성과 모듈화를 개선하는 강력한 도구이다. 프록시 패턴은 특정 객체에 대한 접근 제어 및 부가 기능을 추가하는 데 중점을 두고 있으며, AOP는 애플리케이션 전반에 걸쳐 반복되는 관심사를 모듈화하는 데 유용하다.

    다음 글에서는 네트워크 프록시 개념과 활용을 공부하겠다.

     

     

    출처

    https://study0304.tistory.com/80

     

    [Spring] 흐름으로 이해해보는 AOP와 프록시

    AOP의 개념에 대해 쉽게 이해하고 싶은 사람은 링크를 참조하길 바람 목차 1. AOP(Aspect Oriented Programming)란? 2. AOP와 프록시 패턴 3. 프록시 패턴의 단점 해결: 다이내믹 프록시 4. 다이내믹 프록시 단

    study0304.tistory.com

    https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EB%88%84%EA%B5%AC%EB%82%98-%EC%89%BD%EA%B2%8C-%EB%B0%B0%EC%9A%B0%EB%8A%94-Dynamic-Proxy-%EB%8B%A4%EB%A3%A8%EA%B8%B0#cglib_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%86%8C%EA%B0%9C

     

    ☕ 누구나 쉽게 배우는 Dynamic Proxy 다루기

    Java Dynamic Proxy 자바 프로그래밍의 디자인 패터중 하나인 프록시 패턴은 초기화 지연, 접근 제어, 로깅, 캐싱 등, 기존 대상 원본 객체를 수정 없이 추가 동작 기능들을 가미하고 싶을 때 사용하는

    inpa.tistory.com

    https://www.youtube.com/watch?v=Hm0w_9ngDpM

     

    '디자인패턴' 카테고리의 다른 글

    프록시 패턴이란?  (1) 2025.01.24
    싱글톤 패턴  (0) 2025.01.08
    디자인 패턴이란?  (0) 2025.01.07