728x90
Within
within 지시자는 특정 타입 내의 조인 포인트에 대한 매칭을 제한한다. 쉽게 이야기해서 해당 타입이 매칭 되면 그 안의 메서드(조인 포인트)들이 자동으로 매칭 된다. 문법은 단순한데 execution에서 타입 부분만 사용한다고 보면 된다
Test
@Test
public void withinExact(){
pointcut.setExpression("within(hello.aop.member.MemberServiceImpl)");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void withinStar(){
pointcut.setExpression("within(hello.aop.member.*Service*)");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void withinSubPackage(){
pointcut.setExpression("within(hello.aop..*)");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
within 사용시 주의해야 할 점이 있다. 표현식에 부모 타입을 지정하면 안 된다는 점이다. 정확하게 타입이 맞아야 한다. 이 부분에서 execution과 차이가 난다.
@Test
@DisplayName("타겟의 타입에만 직접 적용, 인터페이스를 선정하면 안된다")
public void withSuperTypeFalse(){
pointcut.setExpression("within(hello.aop.member.MemberService)");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
}
@Test
@DisplayName("타겟의 타입에만 직접 적용, 인터페이스를 선정 가능")
public void executionSuperTypeTrue(){
pointcut.setExpression("execution(* hello.aop.member.MemberService.*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
부모 타입(여기서는 MemberService 인터페이스) 지정시 within 은 실패하고, execution 은 성공하는 것을 확인할 수 있다.
Args
args : 인자가 주어진 타입의 인스턴스인 조인 포인트로 매칭
기본 문법은 execution 의 args 부분과 같다.
차이점
- execution 은 파라미터 타입이 정확하게 매칭 되어야 한다. execution 은 클래스에 선언된 정보를 기반으로 판단한다.
- args 는 부모 타입을 허용한다. args는 실제 넘어온 파라미터 객체 인스턴스를 보고 판단한다
Test
private AspectJExpressionPointcut pointcut(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return pointcut;
}
@Test
public void args() {
//hello(String)과 메칭
assertThat(pointcut("args(String)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
assertThat(pointcut("args(Object)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
assertThat(pointcut("args()").matches(helloMethod, MemberServiceImpl.class)).isFalse();
assertThat(pointcut("args(..)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
assertThat(pointcut("args(*)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
assertThat(
pointcut("args(String, ..)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- pointcut() : AspectJExpressionPointcut 에 포인트 컷은 한 번만 지정할 수 있다
- 메서드로 추출해서 사용
Execution VS Args 비교 Test
/**
* execution(* *(java.io.Serializable)): 메서드의 시그니처로 판단 (정적) args(java.io.Serializable): 런타임에 전달된
* 인수로 판단 (동적)
*/
@Test
public void argsVsExecution() {
//Args
assertThat(pointcut("args(String)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
assertThat(pointcut("args(java.io.Serializable)").matches(helloMethod,
MemberServiceImpl.class)).isTrue();
assertThat(
pointcut("args(Object)").matches(helloMethod, MemberServiceImpl.class)).isTrue();
//Execution
assertThat(pointcut("execution(* *(String))").matches(helloMethod,
MemberServiceImpl.class)).isTrue();
assertThat(pointcut("execution(* *(java.io.Serializable))") //매칭 실패
.matches(helloMethod, MemberServiceImpl.class)).isFalse();
assertThat(
pointcut("execution(* *(Object))").matches(helloMethod,
MemberServiceImpl.class)).isFalse();
}
- 자바가 기본으로 제공하는 String 은 Object , java.io.Serializable의 하위 타입이다.
- 정적으로 클래스에 선언된 정보만 보고 판단하는 execution(* *(Object)) 는 매칭에 실패한다
- 동적으로 실제 파라미터로 넘어온 객체 인스턴스로 판단하는 args(Object) 는 매칭에 성공한다. (부모 타입 허용)
- 참고
- Args 지시자는 단독으로 사용되기 보다는 파라미터 바인딩에서 주로 사용된다.
728x90
'스프링 핵심 원리(고급편)' 카테고리의 다른 글
| Ch11. 스프링 AOP(포인트컷) - @annotation, @args, bean (0) | 2022.04.20 |
|---|---|
| Ch11. 스프링 AOP(포인트컷) - @target, @within (0) | 2022.04.20 |
| Ch11. 스프링 AOP(포인트컷) - execution (0) | 2022.04.20 |
| Ch11. 스프링 AOP(포인트컷) - 포인트컷 지시자 (0) | 2022.04.20 |
| Ch10. 스프링 AOP(구현) - 스프링 AOP 구현(어드바이스 종류) (0) | 2022.04.19 |