Spring

[Spring] 스프링 AOP(7) - AspectJ 표현식

재담 2022. 2. 20. 01:24

AspectJ의 Pointcut 표현식

AspectJ는 Pointcut을 명시할 수 있는 다양한 명시자를 제공하는데, 스프링은 메서드 호출과 관련된 명시자만을 지원하고 있다.

 

execution 명시자

execution명시자는 Advice를 적용할 메서드를 명시할 때 사용되며, 기본 형식은 다음과 같다.

더보기

execution(수식어패턴? 리턴타입패턴 클래스이름패턴?메서드이름패턴(파라미터패턴)

"수식어패턴" 부분은 생략 가능한 부분으로서 public, protected 등이 올 수 있는데 스프링은 public 메서드에만 적용 가능하기 때문에 사실상 public 이외의 값은 의미가 없다.

 

각 패턴은 "*"을 이용하여 모든 값을 표현할 수 있다. 또한, ".."을 이용하여 0개 이상이라는 의미를 표현할 수 있다.

 

예시를 살펴보자.

 

더보기

execution(public void set*(..))

리턴 타입이 void이고 메서드 이름이 set으로 시작하고, 파라미터가 0개 이상인 메서드 호출. 파라미터 부분에 ".."을 사용하여 파라미터가 0개 이상인 것을 표현하였다.

 

더보기

execution(* com.mypackage.*.*())

com.mypackage 패키지의 파라미터가 없는 모든 메서드 호출

 

더보기

execution(* com.mypackage..*.*(..))

com.mypackage 패키지 및 하위 패키지에 있는, 파라미터가 0개 이상인 모든 메서드 호출. 패키지 부분에 ".."을 사용하여 해당 패키지 또는 하위 패키지를 표현하였다.

 

더보기

execution(Integer com.mypackage.board.WriteArticleService.write(..))

리턴 타입이 Integer인 WriteArticleService 인터페이스의 write() 메서드 호출

 

더보기

execution(* get*(*))

이름이 get으로 시작하고 1개의 파라미터를 갖는 메서드 호출

 

더보기

execution(* get*(*, *))

이름이 get으로 시작하고 2개의 파라미터를 갖는 메서드 호출

 

더보기

execution(* read*(Integer, ..))

메서드 이름이 read로 시작하고, 첫 번째 파라미터 타입이 Integer이며, 1개 이상의 파라미터를 갖는 메서드 호출

 

 

within 명시자

within 명시자는 특정 타입에 속하는 메서드를 Pointcut으로 설정할 때 사용된다.

 

예시를 살펴보자.

 

더보기

within(com.mypackage.board.WriteArticleService)

WriteArticleService 인터페이스의 모든 메서드 호출

 

더보기

within(com.mypackage.board.*)

com.mypackage.board 패키지에 있는 모든 메서드 호출

 

더보기

within(com.mypackage.board..*)

com.mypackage.board 패키지 및 그 하위 패키지에 있는 모든 메서드 호출

 

 

bean 명시자

bean 명시자는 스프링에서 추가적으로 제공하는 명시자로서, 스프링 빈 이름을 이용하여 Pointcut을 정의한다. bean 명시자는 빈 이름의 패턴을 갖는다.

 

예시를 살펴보자.

 

더보기

bean(writeArticleService)

이름이 writeArticleService인 빈의 메서드 호출

 

더보기

bean(*ArticleService)

이름이 ArticleService로 끝나는 빈의 메서드 호출

 

 

Pointcut의 조합

각각의 표현식은 "&&" 또는 "||" 연산자를 이용하여 연결할 수 있다.

 

예시를 살펴보자.

 

@AfterThrowing(pointcut="execution(public * get*()) && execution(public void set*(..))")
public void throwing() {
    // 이하 생략
    ...
}

@Aspect 어노테이션을 이용하는 경우 "&&" 연산자를 사용하여 두 표현식을 모두 만족하는 JoinPoint에만 Advice가 적용되도록 할 수 있다.

 

<aop:pointcut id="propertyMethod"
    expression="execution(public * get*()) &amp;&amp; execution(public void set*(..))"
/>

XML 스키마를 이용하여 "&&" 연산자를 사용했는데 XML 문서는 "&&"를 "&amp;&amp;"로 표현하였다. 이는 불편하므로 스프링 설정 파일에서 "and"와 "or"를 사용할 수 있도록 하고 있다. 따라서 다음과 같이 입력할 수 있다.

<aop:pointcut id="propertyMethod"
    expression="execution(public * get*()) and execution(public void set*(..))"
/>

 

@Pointcut 어노테이션을 사용하는 경우 메서드 이름을 이용해서 쉽게 두 개 이상의 Pointcut을 조합할 수 있다.

@Pointcut("execution(public * *(..))")
private void publicMethod() {}

@Pointcut("within(com.mypackage.board..*)")
private void inBoard() {}

@Pointcut("publicMethod() && inBoard()")
private void boardPublicOperation() {}

 

@Pointcut 어노테이션을 이용하면 XML 스키마를 이용하는 경우에 비해 Pointcut의 조합 및 자새용이 쉽기 때문에 공통으로 사용되는 Pointcut은 @Pointcut 어노테이션을 이용해서 표현하는 것이 좋다.


Reference

  • 웹 개발자를 위한 Spring 4.0 프로그래밍 (최범균 저)