스프링에서 PointCut을 적용할 때 String의 equal로 여러개의 클래스나 메서드를 포괄하기에는 쉽지 않은 일인데 이러한 것을 해결해 주는 것이 AspectJ 표현식을 이용하는 것이다.
[AspectJ 표현식을 사용하지 않은 AOP 예제]
https://honeyinfo7.tistory.com/104
AspectJ는 PARC에서 개발한 자바 프로그래밍 언어용 관점 지향 프로그래밍 (AOP) 확장 기능이다. 이클립스 재단 오픈 소스 프로젝트에서 독립형 또는 이클립스로 통합하여 이용 가능하다. AspectJ는 최종 사용자를 위한 단순함과 이용성을 강조함으로써 폭넓게 사용되는 AOP에 대한 데 팍토 표준이 되었다. 자바 계열 문법을 사용하며 2001년 초기 출시 이후 횡단 구조를 표시하기 위한 IDE 연동을 포함하였다.
_위키피디아
스프링에서 사용하는 AOP도 AspectJ 표현식을 쓸 수 있는데 위의 문장처럼 AspectJ가 AOP에 대한 사실상 표준이기 때문이렸다. 이 글에서는 AspectJ의 표현식에 대해 알아보는데 사실상 execution()을 이용한 표현식이 가장 많이 쓰이므로 해당 사용 예제를 작성해 보겠다.
[] : 옵션항목이기 때문에 생략이 가능하다는 의미
| : OR 조건
execution([접근제한자 패턴] 리턴값의 타입패턴 [클래스, 패키지 이름패턴.]메소드이름패턴 (파라미터 타입패턴|"..",...)
접근제한자 패턴 : public, private, protected
리턴값의 타입패턴 : 리턴되는 자료형
클래스, 패키지 이름 패턴 : 패키지 및 클래스명(생략가능)
메소드 이름 패턴 : 메서드의 이름
파라미터 타입 패턴 : 파라미터의 타입
이러한 표현식 같은 것은 이렇게 설명을 보는 것 보다 예제를 보는것이 이해가 빠를 수 있다. 다음은 토비의 스프링에 나온 예제이다.
예제 사용중 주의사항)
Maven pom.xml에서 aspectj Dependency 설정시에 version 태그의 버전을 일치시켜야 함.
[pom.xml]
<!-- AspectJ RunTime -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJ Weaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJ Tools -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
[Bean.java]
package springbook.test;
public class Bean {
public void method() {}
}
[TargetInterface.java]
package springbook.test;
public class Target implements TargetInterface{
@Override
public void hello() {
// TODO Auto-generated method stub
}
@Override
public void hello(String a) {
// TODO Auto-generated method stub
}
@Override
public int minus(int a, int b) throws RuntimeException {
// TODO Auto-generated method stub
return 0;
}
@Override
public int plus(int a, int b) {
// TODO Auto-generated method stub
return 0;
}
public void method() {}
}
[TargetInterface.java]
package springbook.test;
public interface TargetInterface {
public void hello();
public void hello(String a);
public int minus(int a,int b) throws RuntimeException;
public int plus(int a,int b);
}
[TestAspectJExpression.java]
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.internal.runners.JUnit4ClassRunner;
import org.junit.runner.RunWith;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.test.context.ContextConfiguration;
@RunWith(JUnit4ClassRunner.class)
@ContextConfiguration
public class TestAspectJExpression {
@Test
public void methodSignaturePointcut() throws NoSuchMethodException, SecurityException {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(public String com.copocalypse.web.service.MyServiceImpl.action(String)) ");
// MyServiceImpl.action()
assertThat(pointcut.getClassFilter().matches(MyServiceImpl.class)&&
pointcut.getMethodMatcher().matches(MyServiceImpl.class.getMethod("action", String.class), null),
is(true));
// MyServiceImpl.action1()
assertThat(pointcut.getClassFilter().matches(MyServiceImpl.class)&&
pointcut.getMethodMatcher().matches(MyServiceImpl.class.getMethod("action2", String.class), null),
is(false));
}
}
[예제의 사용 결과]
포인트컷 표현식 |
springbook.test.Target |
springbook.test.Bean |
||||
hello() |
hello(String) |
plus(int,int) |
minus(int,int) |
method() |
method() |
|
execution(* hello(..)) |
ㅇ |
ㅇ |
|
|
|
|
execution(* hello()) |
ㅇ |
|
|
|
|
|
execution(* hello(String)) |
|
ㅇ |
|
|
|
|
execution(* meth*(..)) |
|
|
|
|
ㅇ |
ㅇ |
execution(* *(int,int)) |
|
|
ㅇ |
ㅇ |
|
|
execution(* *()) |
ㅇ |
|
|
|
ㅇ |
ㅇ |
execution(* springbook.test.Target.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
|
execution(* springbook.test.*.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
execution(* springbook.test..*.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
execution(* springbook..*.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
execution(* com..*.*(..)) |
|
|
|
|
|
|
execution(* *..Target.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
|
execution(* *..*Tar*.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
|
execution(* *..*get.*(..)) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
|
execution(* *..B*.*(..)) |
|
|
|
|
|
ㅇ |
execution(* *..TargetInterface.*(..)) (TargetInterface를 구현한 메서드만) |
ㅇ |
ㅇ |
ㅇ |
ㅇ |
|
|
execution(* *(..) throws Runtime*) |
|
|
|
ㅇ |
|
ㅇ |
execution(int *(..)) |
|
|
ㅇ |
ㅇ |
|
|
execution(void *(..)) |
ㅇ |
ㅇ |
|
|
ㅇ |
ㅇ |
결론적으로 AspectJ에서 execution() 표현식을 이용하면 클래스 및 메서드를 광범위하게 찾을 수 있다.