이전까지, Spring AOP를 사용하는 방법에 대해서 알아보았습니다.
이전 글
execution
: 메소드 실행 조인 포인트를 매칭합니다.within
: 특정 타입 내의 조인 포인트를 매칭합니다.args
: 인자가 주어진 타입의 인스턴스인 조인 포인트를 매칭합니다.this
: 스프링 빈 객체를 대상으로 하는 조인 포인트를 매칭 합니다.target
: Target 객체를 대상으로 하는 조인 포인트를 매칭 합니다.@target
: 실행 객체의 클래스에 주어진 타입의 애노테이션이 있는 조인 포인트를 매칭 합니다.@within
: 주어진 애노테이션이 있는 타입 내 조인 포인트를 매칭 합니다.@annotation
: 매서드가 주어진 애노테이션을 가지고 있는 조인 포인트를 매칭 합니다.@args
: 전달된 실제 인수의 런타임 타입이 주어진 타입의 애노테이션을 갖는 조인포인트를 매칭 합니다.bean
: 스프링 전용 포인트컷 지시자, 빈의 이름으로 포인트컷을 지정 합니다.예제에 사용한 코드 : Github
- baekgwa/springaop/global/aop/pointcuts/ExecutionPointcut.java 참조
- baekgwa/springaop/global/aop/aspects/AspectV5.java 참조
- test코드) baekgwa.springaop.ExecutionTest 참조
하나씩 Case별로 Aspect 등록해서 확인해보려 했지만,,,, 너무 양이 많아 포기하고 테스트 코드로 진행 하겠습니다.
접근제한자
반환타입
패키지경로
.메서드이름
(파라미터...
) throws 예외 class
")execution("public String baekgwa.web.cart.CartController.saveNewItem(Integer))");
public 접근제한자
로, String을 반환
하며, ~~경로의 패키지중
, CartController
클래스(인터페이스)의 saveNewItem 메서드
의 이름을 가지고, 파라미터는 Integer 타입
을 받는 조건을 만족하면 생성기호 | 설명 | 예시 |
---|---|---|
* | 모든 타입, 메소드 이름, 반환 타입을 의미 | execution(* *.*(..)) |
.. | 0개 이상의 패키지나 파라미터를 의미 | execution(* com.example..*.*(..)) |
. | 단일 패키지 구분자 또는 메소드 이름을 구분 | execution(* com.example.service.*(..)) |
(..) | 0개 이상의 파라미터를 의미 | execution(* com.example..*.*(String, ..)) |
Item | 구체적인 타입 또는 파라미터를 의미 | execution(* com.example..*.*(Item)) |
기호 | 설명 | 예시 |
---|---|---|
[접근제어자] | 메소드의 접근 제어자는 생략 가능 | execution(* com.example.service.*.*(..)) |
[반환타입] | 메소드의 반환 타입은 생략 가능 | execution(* com.example.service.*.*(..)) |
[패키지명] | 패키지 경로는 생략 가능 (루트 패키지 포함) | execution(* *.*(..)) |
[클래스명] | 클래스명은 생략 가능 (모든 클래스 포함) | execution(* com.example.service.*(..)) |
[메소드명] | 메소드 이름은 생략 가능 (모든 메소드 포함) | execution(* com.example.service.*(..)) |
[파라미터 목록] | 파라미터 목록은 생략 가능 (모든 파라미터 포함) | execution(* com.example.service.*.*(..)) |
execution(* com.example.service.*.*(..))
는 모든 접근 제어자의 메소드를 포함합니다.execution(public * com.example.service.*.*(..))
는 모든 반환 타입의 메소드를 포함합니다.execution(* *.*(..))
는 모든 패키지의 메소드를 포함합니다.execution(* com.example.service.*(..))
는 모든 클래스를 포함합니다.execution(* com.example.service.*(..))
는 모든 메소드를 포함합니다.execution(* com.example.service.*.*(..))
는 모든 파라미터 목록을 포함합니다.해당 부분을 포스팅하면, 길이가 너무 길어져 Github 주소로 대체합니다.
Github
- test코드) baekgwa.springaop.ExecutionTest 참조
예제에 사용한 코드 : Github
- test코드) baekgwa.springaop.WithinTest 참조
기호 | 설명 | 예시 |
---|---|---|
within(Type) | 지정된 타입의 객체에 속한 메소드 호출을 매칭 | within(baekgwa.springaop.web.cart.CartServiceImpl) CartServiceImpl 클래스의 모든 메소드 호출 매칭 |
within(Package..*) | 지정된 패키지와 그 하위 패키지의 모든 타입과 메소드 호출을 매칭 | within(baekgwa.springaop.web..*) baekgwa.springaop.web 패키지와 그 하위 패키지의 모든 클래스의 메소드 호출 매칭 |
within(Type*) | 지정된 패키지 내에서 이름이 지정된 패턴을 가진 타입의 메소드 호출을 매칭 | within(baekgwa.springaop.web..*Service*) baekgwa.springaop.web 패키지 내의 모든 Service 가 포함된 클래스의 메소드 호출 매칭 |
within(Type) 은 단일 클래스의 모든 메소드를 매칭하며, within(Package..*) 는 패키지 및 하위 패키지의 모든 클래스를 매칭합니다. | within(Type) 과 within(Package..*) 는 각각 단일 클래스와 패키지의 범위를 매칭합니다. | within(com.example..*) 는 com.example 패키지와 그 하위 패키지의 모든 클래스의 메소드 호출을 포함합니다. |
within 표현식은 클래스와 패키지의 범위를 설정하며, 메소드 시그니처나 파라미터 타입과는 관련이 없습니다. | within 표현식은 메소드 시그니처나 파라미터 타입에 영향을 미치지 않으며, 단순히 클래스 또는 패키지 범위에 따라 포인트컷을 설정합니다. | within(com.example.service..*) 는 com.example.service 패키지 및 하위 패키지의 모든 클래스에 대한 포인트컷을 설정합니다. |
within(baekgwa.springaop.web.cart.CartServiceImpl)
은 CartServiceImpl
클래스의 모든 메소드 호출을 매칭합니다.within(baekgwa.springaop.web..*)
은 baekgwa.springaop.web
패키지와 그 하위 패키지의 모든 클래스의 메소드 호출을 매칭합니다.within(baekgwa.springaop.web..*Service*)
은 baekgwa.springaop.web
패키지 내에서 Service
가 이름에 포함된 클래스의 메소드 호출을 매칭합니다.@Test
@DisplayName("within() test1")
void withinMatchTest1() {
pointcut.setExpression("within(baekgwa.springaop.web.cart.CartServiceImpl)");
assertThat(pointcut.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
}
@Test
@DisplayName("within() test2")
void withinMatchTest2() {
pointcut.setExpression("within(baekgwa.springaop.web..*Service*)");
assertThat(pointcut.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
}
결과는 다음과 같이 성공합니다.
args
: 인자가 주어진 타입의 인스턴스인 조인 포인트로 매칭execution
의 args
부분과 같습니다.기호 | 설명 | 예시 |
---|---|---|
args(Type) | 메소드의 인자가 주어진 타입의 인스턴스인 조인 포인트 매칭 | args(baekgwa.springaop.web.Item) Item 타입의 인자를 가진 메소드 호출 매칭 |
args(Type, ..) | 첫 번째 인자가 주어진 타입이고, 나머지 인자는 상관없는 조인 포인트 매칭 | args(String, baekgwa.springaop.web.Item) 첫 번째 인자가 String 타입, 두 번째가 Item 타입인 메소드 호출 매칭 |
args(.., Type) | 마지막 인자가 주어진 타입인 조인 포인트 매칭 | args(.., baekgwa.springaop.web.Item) 마지막 인자가 Item 타입인 메소드 호출 매칭 |
args(.., Type, ..) | 중간에 주어진 타입의 인자가 있는 조인 포인트 매칭 | args(.., baekgwa.springaop.web.Item, ..) 중간에 Item 타입의 인자가 있는 메소드 호출 매칭 |
args(baekgwa.springaop.web.Item)
은 메소드의 모든 인자가 Item
타입인 경우를 매칭합니다.args(String, baekgwa.springaop.web.Item)
은 첫 번째 인자가 String
이고 두 번째 인자가 Item
인 메소드를 매칭합니다.args(.., baekgwa.springaop.web.Item)
은 마지막 인자가 Item
타입인 메소드를 매칭합니다.args(.., baekgwa.springaop.web.Item, ..)
은 인자 목록의 중간에 Item
타입이 있는 메소드를 매칭합니다.execution
과 다르게 args
는, 파라미터 타입에 부모타입을 허용 합니다.execution
은 정확하게 매칭되는 파라미터를 넣어줘야 됩니다. @Test
void argsVsExecutionTest() {
//args
//부모타입을 허용. 실제 넘어온 파라미터 객체 인스턴스를 보고 판단.
//Item 참조 - 성공
assertThat(pointcut("args(baekgwa.springaop.web.cart.domain.Item)")
.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
//Interface 참조 - 성공
assertThat(pointcut("args(baekgwa.springaop.web.cart.CartService)")
.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
//최상위 Object - 성공
assertThat(pointcut("args(Object)")
.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
//execution
//정확하게 매칭되는 것만 매칭
//Item 참조 - 성공
assertThat(pointcut("execution(* *(baekgwa.springaop.web.cart.domain.Item))")
.matches(saveNewItemMethod, CartServiceImpl.class)).isTrue();
//Interface 참조 - 실패
assertThat(pointcut("execution(* *(baekgwa.springaop.web.cart.CartService))")
.matches(saveNewItemMethod, CartServiceImpl.class)).isFalse();
//최상위 Object - 실패
assertThat(pointcut("execution(* *(Object))")
.matches(saveNewItemMethod, CartServiceImpl.class)).isFalse();
}
해당 부분을 포스팅하면, 길이가 너무 길어져 Github 주소로 대체합니다.
Github
- test코드) baekgwa.springaop.ArgsTest 참조
클래스
를 조인 포인트로 지정합니다.@target
: 인스턴스의 모든 메서드를 조인 포인트로 적용. (즉, 부모로부터 상속 받은 메서드까지 어드바이스 적용)@within
: 자기 자신의 클래스에 정의된 메서드에만 어드바이스를 적용.package baekgwa.springaop.global.aop.annotation;
~~~
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAnnotation {
}
메서드
를 조인 포인트로 지정 합니다.package baekgwa.springaop.global.aop.annotation;
~~~
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodAnnotation {
}