본문 바로가기
Spring

[Spring] AOP pointcut 표현식

by Real Iron 2019. 2. 13.

출처 : http://blog.naver.com/PostView.nhn?blogId=chocolleto&logNo=30086024618&categoryNo=29&viewDate=&currentPage=1&listtype=0


6. AspectJ의 Pointcut 표현식

  □ POJO 클래스를 이용하여 AOP를 적용하는 두 가지 방법

    - XML 스키마를 이용하여 Aspect를 설정하는 방법.
    - @Aspect 어노테이션을 이용하여 Aspect를 설정하는 방법.
    ■ 두 방법의 공통점
      - AspectJ의 문법을 이용하여 Pointcut을 설정.
    ■ <aop:태그>를 이용하여 Aspect를 설정하는 경우
      - execution 명시자를 이용하여 Advice가 적용될 Pointcut을 설정.

 <aop:aspect id="cacheAspect" ref="cache">
    <aop:around method="read"
        pointcut="execution(public * kame.spring.chap03.core.*.readArticle(..))" />
 </aop:aspect>


  □ AspectJ의 Pointcut 표현식
    - AspectJ는 Pointcut을 명시할 수 있는 다양한 명시자를 제공.
    - 스프링은 메서드 호출과 관련된 명시자만을 지원.
    ■ execution 명시자
      - Advice를 적용할 메서드를 명시할 때 사용.
      ○ 기본 형식

 execution(수식어패턴? 리턴타입패턴 패키지패턴?이름패턴(파라미터패턴)

        ● 수식어 패턴
          - 생략가능한 부분.
          - public, protected 등이 옴.
        ● 리턴타입패턴
          - 리턴 타입을 명시
        ● 클래스이름 패턴, 이름패턴
          - 클래스 이름 및 메서드 이름을 패턴으로 명시.
        ● 파라미터패턴
          - 매칭될 파라미터에 대해서 명시.
      ○ 특징
        - 각 패턴은 '*'를 이용하여 모든 값을 표현.
        - '..'을 이용하여 0개 이상이라는 의미를 표현.
      ○ 설정 예
        ● execution(public void set*(..))
          - 리턴 타입이 void이고 메서드 이름이 set으로 시작하고, 파라미터가 0개 이상인 메서드 호출.
        ● execution(* kame.spring.chap03.core.*.*())
          - kame.spring.chap03.core 패키지의 파라미터가 없는 모든 메서드 호출.
        ● execution(*.kame.spring.chap03.core..*.*(..))
          - kame.spring.chap03.core 패키지 및 하위 패키지에 있는 파라미터가 0개 이상인 메서드 호출.
        ● execution(Integer kame.spring.chap03.core.WriteArticleService.write(..))
          - 리턴 타입이 Integer인 WriteArticleService 인터페이스의 write() 메서드 호출.
        ● execution(* get*(*))
          - 이름이 get으로 시작하고 1개의 파라미터를 갖는 메서드 호출.
        ● execution(* get*(*, *))
          - 이름이 get으로 시작하고 2개의 파라미터를 갖는 메서드 호출.
        ● execution(* read*(Integer, ..))
          - 메서드 이름이 read로 시작하고, 첫 번째 파라미터 타입이 Integer이며, 1개 이상의 파라미터를 갖는 메서드 호출.
    ■ within 명시자
      - 메서드가 아닌 특정 타입에 속하는 메서드를 Pointcut으로 설정할 때 사용.
      ○ 설정 예
        ● within(kame.spring.chap03.core.WriteArticleService)
          - WriteArticleService 인터페이스의 모든 메서드 호출.
        ● within(kame.spring.chap03.core.*)
          - kame.spring.chap03.core 패키지에 있는 모든 메서드 호출.
        ● within(kame.spring.chap03.core..*)
          - kame.spring.chap03.core 패키지 및 그 하위 패키지에 있는 모든 메서드 호출.
    ■ bean 명시자
      - 스프링 2.5 버전부터 스프링에서 추가적으로 제공하는 명시자.
      - 스프링 빈 이름을 이용하여 Pointcut을 정의.
      - 빈 이름의 패턴을 갖는다.
      ○ 설정 예
        ● bean(writeArticleService)
          - 이름이 writeArticleService인 빈의 메서드 호출.
        ● bean(*ArticleService)
          - 이름이 ArticleServie로 끝나는 빈의 메서드 호출.
    ■ 표현식 연결
      - 각각의 표현식은 '&&' 나 '||' 연산자를 이용하여 연결 가능.
      ○ @Aspect 어노테이션을 이용하는 경우
        - '&&' 연산자를 사용하여 두 표현식을 모두 만족하는 Joinpoint에만 Advice가 적용.

 @AfterThrowing(
    pointcut = "execution(public * get*()) && execution(public void set*(..))")
 public void throwingLogging() {
    ...
 }

      ○ XML 스키마를 이용하여 Aspect를 설정하는 경우
        - '&&'나 '||' 연산자를 사용.

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

         - XML 문서이기 때문에 값에 들어가는 '&&' '||'를 '&amp;&amp;'로 표현.
         - 설정파일에서 '&&'나 '||' 대신 'and'와 'or'를 사용할 수 있도록 하고 있음.

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


  □ 프록시 구현 방식에 따른 execution 적용 차이

    - Pointcut은 실제로 프록시가 구현하고 있는 인터페이스를 기준으로 Pointcut을 적용.
    - 인터페이스를 구현하고 있는 대상 객체에 대해서 Pointcut을 정의하려면 인터페이스를 기준으로 Pointcut을 작성.

 <aop:aspect id="cacheAspect" ref="cache">
    <aop:around method="read"
        pointcut="execution(public * kame..core.ReadArticleServiceImpl.get*(..))" />
 </aop:aspect>

 <bean id="readArticleService" class="kame.spring.chap03.core.ReadArticleServiceImpl" />

         - ReadArticleServiceImpl 클래스가 ReadArticleService 인터페이스를 구현하고 있다면, 
           <aop:around>는 ReadArticleServiceImpl 클래스의 get으로 시작하는 메서드에 적용.

           (<aop:around> 태그에서 명시한 Pointcut은 readArticleService 빈에는 적용되지 않음.)
         - ReadArticleServiceImpl 클래스가 인터페이스를 구현하고 있지 않다면,
           생성된 프록시는 ReadArticleServiceImpl 클래스를 상속받아 생성됨. (Pointcut은 readArticleService 빈에만 적용.)