본문 바로가기

Java/Spring

스프링 AOP & AspectJ Pointcut 기본 문법

이 문서의 내용

    더보기

    스프링의 AOP는 프록시(Proxy) 방식으로 구현되며 Pointcut을 사용해 실행되는 메소드 범위 Joinpoint를 지정합니다.

    스프링의 Pointcut 기본 문법

    스프링에서는 AspectJ의 Pointcut 문법을 그대로 사용합니다. 기본적인 표현식에는 다음과 같은 규칙이 있습니다.

    execution(<접근 지정자?> <반환 타입> <선언 타입?> <함수 이름><(파라미터)> <예외?>)

    ? 심볼은 생략 가능을 의미합니다. ? 심볼이 없으면 필수적으로 명시해야하는 구문입니다.

    표현식에서 필수 구성만 포함하면 다음과 같이 축약됩니다.

    execution(<반환 타입> <함수 이름><(파라미터)>)

    스프링에서는 Pointcut의 접근 지정자로 public만 사용 할 수 있습니다.

    • 그 외 protected | private | default는 사용 할 수 없습니다.

    여러 가지 심볼을 사용해 표현식을 확장합니다.

    • * 심볼은 매칭 가능한 모든 것을 의미합니다.
    • .. 심볼은 0개 이상 또는 하위 경로를 포함의 의미로 사용합니다.
    더보기

    execution Pointcut 지시자(PCD, Pointcut Designator)입니다. 모든 Pointcut 구문은 Designator로 시작합니다.

    전체 PCD 유형은 docs.spring.io: Declaring a Pointcut(Supported Pointcut Designator)를 참고합니다.

    execution 예시 1: 모든 Joinpoint와 매칭

    프로젝트의 모든 함수와 매칭되도록 Joinpoint를 구성합니다.

    @Pointcut("execution(* *(..))")
    private void pointcutMethod() { }
    구분 접근 지정자? 반환 타입 선언 타입? 함수 이름 (파라미터) 예외 ?
    구문 생략 * 생략 * (..) 생략
    비고 생략 모든 반환 타입과 매칭 생략 모든 함수 이름과 매칭 파라미터가 0개 이상과 매칭 생략

    execution 예시 2: 지정된 Joinpoint와 매칭

    프로젝트에서 유일한 함수와 매칭되도록 Joinpoint를 구성합니다.

    @Pointcut("execution(public void com.io.test.HelloWord.helloworld(String, String))")
    private void pointcutMethod() { }
    구분 접근 지정자? 반환 타입 선언 타입? 함수 이름 (파라미터) 예외 ?
    구문 public void com.io.test.HelloWorld helloworld (String, String) 생략
    비고 public 접근 지정자와 매칭 void 반환 타입과 매칭 com.io.test 패키지의
    HelloWorld 클래스와 매칭
    helloworld 함수 이름과 매칭 두 개의 String 파라미터와 매칭 예외 처리 없음

    execution 예시 3: 특정 패키지 이하의 Joinpoint와 매칭

    프로젝트의 특정 패키지 이하에서 실행되는 함수와 매칭되도록 Joinpoint를 구성합니다.

    @Pointcut("execution(* com.io..*.*(..))")
    private void pointcutMethod() { }
    구분 접근 지정자? 반환 타입 선언 타입? 함수 이름 (파라미터) 예외 ?
    구문 생략 * com.io..*. * (..) 생략
    비고 생략 모든 반환 타입과 매칭 com.io 패키지와 그 이하(..)의
    모든 클래스(*.)와 매칭
    모든 함수 이름과 매칭 파라미터가 0개 이상과 매칭 생략

    within - 패키지, 클래스를 매칭하는 Designator

    within을 사용하면 특정 클래스에 속하는 모든 함수를 Joinpoint로 구성합니다.

    예를 들어 com.io.test 패키지HelloWolrd 클래스의 모든 함수와 Joinpoint를 구성하려면 다음과 같이 작성합니다.

    @Pointcut("within(com.io.test.HelloWorld)")
    private void pointcutMethod() { }

    com.io.test 패키지모든 클래스가 실행하는 모든 함수와 Joinpoint를 구성합니다.

    @Pointcut("within(com.io.test.*)")
    private void pointcutMethod() { }

    bean - Bean 이름과 매칭하는 Designator

    bean을 사용하면 특정 Bean이 실행하는 모든 함수를 Joinpoint로 구성합니다.

    예를 들어 hello로 시작하는 Bean 이름의 Bean이 실행하는 모든 함수와 Joinpoint를 구성 할 수 있습니다.

    @Pointcut("bean(hello*)")
    private void pointcutMethod() { }
    더보기

    bean은 스프링 2.5부터 사용 가능합니다.

    Pointcut 표현식의 결합

    여러 개의 Pointcut 표현식을 하나로 결합하여 Joinpoint를 구성 할 수 있습니다.

    @Pointcut("execution(public * *(String, String)")
    private void pointcutMethod0() { }
    
    @Pointcut("within(com.io.test.*)")
    private void pointcutMethod1() { }
    코드 비고
    Line 1:2 pointcutMethod0 execution PCD를 사용해 Joinpoint를 구성하고 있습니다.
    public 접근 지정자두 개의 String 파라미터를 갖는 함수를 지정합니다.
    Line 4:5 pointcutMethod1 within PCD를 사용해 Joinpoint를 구성하고 있습니다.
    com.io.test 패키지에 위치한 모든 클래스가 실행하는 함수를 지정합니다.

    표현식을 결합하려면 AND(&&) OR(||) NOT(!)을 사용합니다.

    &&를 사용하면 위 예시의 Pointcut의 조건을 모두 만족하는 새로운 Pointcut을 지정 할 수 있습니다.

    @Pointcut("pointcutMethod0() && pointcutMethod1()")
    private void combinedPointcutMethod() { }
    더보기

    @Pointcut에서는 다른 Pointcut의 표현식을 참조 할 수 있습니다.

    예를 들어 다음 구문에서는 anotherPointcutMethod는 표현식을 직접 작성하는 대신 pointcutMethod0()의 표현식을 사용합니다.

    @Pointcut("pointcutMethod0()")
    private void anotherPointcutMethod() { }

    이때 참조하는 함수의 접근 지정자가 중요합니다.

    동일한 패키지에서는 소스가 되는 함수는 protected 또는 public으로 지정합니다. 다른 패키지에서는 소스가 되는 함수는 public으로 지정되어야 합니다.

    정리 및 복습

    • 스프링의 AOP는 프록시(Proxy) 방식으로 구현되며 Pointcut을 사용해 실행되는 메소드 범위 Joinpoint를 지정합니다.
    • 스프링에서는 AspectJ의 Pointcut 문법을 그대로 사용합니다. 기본적인 표현식에는 다음과 같은 규칙이 있습니다.
    execution(<접근 지정자?> <반환 타입> <선언 타입?> <함수 이름><(파라미터)> <예외?>)
    • ? 심볼은 생략 가능을 의미합니다. ? 심볼이 없으면 필수적으로 명시해야하는 구문입니다.
    execution(<반환 타입> <함수 이름><(파라미터)>)
    • * 심볼은 매칭 가능한 모든 것을 의미합니다.
    • .. 심볼은 0개 이상 또는 하위 경로를 포함의 의미로 사용합니다.
    • execution Pointcut 지시자(PCD, Pointcut Designator)입니다. 모든 Pointcut 구문은 Designator로 시작합니다.
    • 전체 PCD 유형은 docs.spring.io: Declaring a Pointcut(Supported Pointcut Designator)를 참고합니다.
    • within PCD는 특정 패키지와 클래스를 Joinpoint로 매칭합니다.
    • bean PCD는 특정 Bean 이름을 Joinpoint로 매칭합니다.
    • 여러 개의 Pointcut을 결합하여 표현식을 만들 수 있습니다. 구문으로는 AND(&&) OR(||) NOT(!)을 사용합니다.
    @Pointcut("pointcutMethod0() && pointcutMethod1()")
    private void combinedPointcutMethod() { }