728x90
execution 문법
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?namepattern(param-pattern)
throws-pattern?)
execution(접근제어자? 반환타입 선언타입?메서드이름(파라미터) 예외?)
- 메서드 실행 조인 포인트를 매칭 한다.
- ? 는 생략할 수 있다.
- * 같은 패턴을 지정할 수 있다.
가장 정확한 포인트 컷
@Test
public void exactMatch() {
//public java.lang.String hello.aop.member.MemberServiceImpl.hello(java.lang.String)
pointcut.setExpression(
"execution(public String hello.aop.member.MemberServiceImpl.hello(String))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- AspectJExpressionPointcut에 pointcut.setExpression을 통해서 포인트 컷 표현식을 적용할 수 있다.
- pointcut.matches(메서드, 대상 클래스)를 실행하면 지정한 포인트 컷 표현식의 매칭 여부를 true , false로 반환한다
가장 많이 생략한 포인트 컷
@Test
public void allMatch() {
pointcut.setExpression(
"execution(* *(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- * 은 아무 값이 들어와도 된다는 뜻이다.
- 파라미터에서 .. 은 파라미터의 타입과 파라미터 수가 상관없다는 뜻이다. ( 0..* ) 파라미터는 뒤에 자세히 정리하겠다
메서드 이름 매칭 관련 포인트 컷
@Test
public void nameMatch(){
pointcut.setExpression(
"execution(* hello(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void nameMatchStar1(){
pointcut.setExpression(
"execution(* hel*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void nameMatchStar2(){
pointcut.setExpression(
"execution(* *el*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void nameMatchFalse(){
pointcut.setExpression(
"execution(* nono(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
}
- 메서드 이름 앞 뒤에 * 을 사용해서 매칭 할 수 있다.
패키지 매칭 관련 포인트 컷
@Test
public void packageExactMatch1(){
pointcut.setExpression(
"execution(* hello.aop.member.MemberServiceImpl.hello(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void packageExactMatch2(){
pointcut.setExpression(
"execution(* hello.aop.*.*(..))"); //패키지가 딱 맞지 않기에 에러
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
}
@Test
public void packageMatchSubPackage1(){
pointcut.setExpression(
"execution(* hello.aop.member..*.*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void packageMatchSubPackage2(){
pointcut.setExpression(
"execution(* hello.aop..*.*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- hello.aop.member.*(1).*(2)
- (1): 타입
- (2): 메서드 이름
- 패키지에서 . , .. 의 차이를 이해해야 한다
- . : 정확하게 해당 위치의 패키지
- .. : 해당 위치의 패키지와 그 하위 패키지도 포함
타입 매칭 - 부모 타입 허용
@Test
public void typeExactMatch() {
pointcut.setExpression("execution(* hello.aop.member.MemberServiceImpl.*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
@Test
public void typeMatchSuperType() {
pointcut.setExpression("execution(* hello.aop.member.MemberService.*(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- typeExactMatch()는 타입 정보가 정확하게 일치하기 때문에 매칭 된다.
- typeMatchSuperType()을 주의해서 보아야 한다.
- execution에서는 MemberService처럼 부모 타입을 선언해도 그 자식 타입은 매칭 된다. 다형성에서 부모 타입 = 자식 타입 이 할당 가능하다는 점을 떠올려보면 된다.
타입 매칭 - 부모 타입에 있는 메서드만 허용
@Test
public void typeMatchInternal() throws NoSuchMethodException {
pointcut.setExpression("execution(* hello.aop.member.MemberServiceImpl.*(..))");
Method internalMethod = MemberServiceImpl.class.getMethod("internal", String.class);
assertThat(pointcut.matches(internalMethod,
MemberServiceImpl.class)).isTrue();
}
@Test
public void typeMatchNoSuperTypeMethodFalse() throws NoSuchMethodException {
pointcut.setExpression("execution(* hello.aop.member.MemberService.*(..))");
Method internalMethod = MemberServiceImpl.class.getMethod("internal", String.class);
assertThat(pointcut.matches(internalMethod,
MemberServiceImpl.class)).isFalse();//자식 타입까지 메칭은 되지만 부모에 선언된 메소드만 적용된다.
}
- typeMatchInternal()의 경우 MemberServiceImpl를 표현식에 선언했기 때문에 그 안에 있는 internal(String) 메서드도 매칭 대상이 된다.
- typeMatchNoSuperTypeMethodFalse()를 주의해서 보아야 한다.
- 이 경우 표현식에 부모 타입인 MemberService를 선언했다. 그런데 자식 타입인 MemberServiceImpl의 internal(String) 메서드를 매칭 하려 한다. 이 경우 매칭에 실패한다. MemberService 에는 internal(String) 메서드가 없다!
- 부모 타입을 표현식에 선언한 경우 부모 타입에서 선언한 메서드가 자식 타입에 있어야 매칭에 성공한다. 그래서 부모 타입에 있는 hello(String) 메서드는 매칭에 성공하지만, 부모 타입에 없는 internal(String)는 매칭에 실패한다
파라미터 매칭
//String 타입의 파라미터 허용
//(String)
@Test
public void argsMatch(){
pointcut.setExpression("execution(* *(String))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
//파라미터가 없어야 한다
//()
@Test
public void argsMatchNoArgs(){
pointcut.setExpression("execution(* *())");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
}
//정확히 하나의 파라미터 허용, 모든 타입 허용
//(XXX)
@Test
public void argsMatchStar(){
pointcut.setExpression("execution(* *(*))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
//숫자와 무관하게 모든 파라미터, 모든 타입 허용
//(), (XXX), (XXX, XXX)
@Test
public void argsMatchAll(){
pointcut.setExpression("execution(* *(..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
//String 타입으로 시작, 숫자와 무관하게 모든 파라미터, 모든 타입 허용
//(String), (String, XXX), (String, XXX, XXX)
@Test
public void argsMatchComplex(){
pointcut.setExpression("execution(* *(String, ..))");
assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
}
- execution 파라미터 매칭 규칙은 다음과 같다.
- (String) : 정확하게 String 타입 파라미터
- () : 파라미터가 없어야 한다.
- (*) : 정확히 하나의 파라미터, 단 모든 타입을 허용한다.
- (*, *) : 정확히 두 개의 파라미터, 단 모든 타입을 허용한다.
- (..) : 숫자와 무관하게 모든 파라미터, 모든 타입을 허용한다. 참고로 파라미터가 없어도 된다. 0..* 로 이해하면 된다.
- (String, ..) : String 타입으로 시작해야 한다. 숫자와 무관하게 모든 파라미터, 모든 타입을 허용한다. 예) (String) , (String, Xxx) , (String, Xxx, Xxx) 허용
728x90
'스프링 핵심 원리(고급편)' 카테고리의 다른 글
| Ch11. 스프링 AOP(포인트컷) - @target, @within (0) | 2022.04.20 |
|---|---|
| Ch11. 스프링 AOP(포인트컷) - within, args (0) | 2022.04.20 |
| Ch11. 스프링 AOP(포인트컷) - 포인트컷 지시자 (0) | 2022.04.20 |
| Ch10. 스프링 AOP(구현) - 스프링 AOP 구현(어드바이스 종류) (0) | 2022.04.19 |
| Ch10. 스프링 AOP(구현) - 스프링 AOP 구현(어드바이스 순서) (0) | 2022.04.19 |