executuon은 포인트컷 지시자 라고 하는데, 포인트컷 지시자에는 execution외에도 여러가지 표현지시자들이 존재한다.

  • execution : 메소드 실행 조인 포인트를 매칭한다. 스프링 AOP에서 가장 많이 사용하고, 기능도 복잡하다.
  • within : 특정 타입 내의 조인 포인트를 매칭한다.
  • args : 인자가 주어진 타입의 인스턴스인 조인 포인트
  • this : 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트
  • target : Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트
  • @target : 실행 객체의 클래스에 주어진 타입의 애노테이션이 있는 조인 포인트
  • @within : 주어진 애노테이션이 있는 타입 내 조인 포인트
  • @annotation : 메서드가 주어진 애노테이션을 가지고 있는 조인 포인트를 매칭
  • @args : 전달된 실제 인수의 런타임 타입이 주어진 타입의 애노테이션을 갖는 조인 포인트
  • bean : 스프링 전용 포인트컷 지시자, 빈의 이름으로 포인트컷을 지정한다.

 

어노테이션 인터페이스 ClassAOP

@Target의 ElementType코드의 위치나 범위를 나타내는 열거형 타입이며, @Target 어노테이션과 함께 사용되어, 어노테이션의 적용 범위를 제한한다.

ElementType.TYPE의 TYPE클래스, 인터페이스(어노테이션 타입 포함), 또는 열거형 선언에 어노테이션을 사용할 수 있음을 나타낸다.

@Retention의 RetentionPolicy어노테이션이 어디까지 유지되는지를 결정하며

SOURCE, CLASS, RUNTIME 으로 나뉜다.

package com.example.demo.member.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAop {
}

어노테이션 인터페이스 MethodAOP

package com.example.demo.member.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) //메서드에 붙이는 어노테이션
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodAop {
    String value();
}

서비스와 구현체

package com.example.demo.member;

public interface MemberService {
    String hello(String param);
}

package com.example.demo.member;

import com.example.demo.member.annotation.ClassAop;
import com.example.demo.member.annotation.MethodAop;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@ClassAop
@Component
public class MemberServiceImpl implements MemberService{
    @Override
    @MethodAop("test value")
    public String hello(String param) {
        return "ok";
    }

    public String internal(String param){
        return "ok";
    }
}

ExecutionTest

package com.example.demo.pointcut;

import com.example.demo.member.MemberServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;

import java.lang.reflect.Method;

@Slf4j
public class ExecutionTest {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    Method helloMethod;

    @BeforeEach
    public void init() throws NoSuchMethodException {
        helloMethod = MemberServiceImpl.class.getMethod("hello",String.class);
    }

    @Test
    void printMethod(){
        //public java.lang.String com.example.demo.member.MemberServiceImpl.hello(java.lang.String)
        log.info("helloMethod={}",helloMethod);
    }

    @Test
    void exactMatch() {
        //public java.lang.String com.example.demo.member.MemberServiceImpl.hello(java.lang.String)
        pointcut.setExpression("execution(public java.lang.String com.example.demo.member.MemberServiceImpl.hello(java.lang.String))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void allMatch() {
        pointcut.setExpression("execution(* *(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void nameMatch() {
        pointcut.setExpression("execution(* hello(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void nameMatchStar1() {
        pointcut.setExpression("execution(* hel*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void nameMatchStar2() {
        pointcut.setExpression("execution(* *el*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void nameMatchFalse() {
        pointcut.setExpression("execution(* nono(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
    }

    @Test
    void packageExactMatch1() {
        pointcut.setExpression("execution(* com.example.demo.member.MemberServiceImpl.hello(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void packageExactMatch2() {
        pointcut.setExpression("execution(* com.example.demo.member.*.*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void packageExactFalse() {
        pointcut.setExpression("execution(* com.example.*.*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isFalse();
    }

    @Test
    void packageMatchSubPackage1() {
        pointcut.setExpression("execution(* com.example..*.*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }

    @Test
    void packageMatchSubPackage2() {
        pointcut.setExpression("execution(* com.example..*.*(..))");
        Assertions.assertThat(pointcut.matches(helloMethod, MemberServiceImpl.class)).isTrue();
    }
}

execution 문법

execution(접근제어자? 반환타입 선언타입?메서드이름(파라미터) 예외?)

  • 메소드 실행 조인 포인트를 매칭한다.
  • ?는 생략할 수 있다.
  • * 같은 패턴을 지정할 수 있다
  • '.' : 정확하게 해당 위치의 패키지
  • '..' : 해당 위치의 패키지와 그 하위 패키지도 포함

 

'Java > 스프링 AOP' 카테고리의 다른 글

스프링 AOP - 매개변수 전달  (0) 2023.09.16
스프링 AOP - execution(2)  (0) 2023.09.14
Spring AOP - 어드바이스 종류  (0) 2023.09.11
Spring AOP - 포인트컷 분리  (0) 2023.09.07
Spring AOP 용어정리  (0) 2023.09.06

+ Recent posts