스프링 부트 - 스프링 AOP 포인트컷 지시자

SeungTaek·2021년 11월 7일
1
post-thumbnail
post-custom-banner

본 게시물은 스스로의 공부를 위한 글입니다.
잘못된 내용이 있으면 댓글로 알려주세요!

📒 포인트컷 지시자의 종류

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

  • 주로 execution을 가장 많이 사용한다.





📒 execution

  • execution( {접근제어자} 반환타입 {선언타입}메서드이름(파라미터) {예외})
    • { }은 생략할 수 있다.
  • *같은 패턴을 지정할 수 있다.

📌 사용 예시

//접근제어자(public) 반환타입(String) 선언타입(hello.aop.member.MemberServiceImpl).메서드이름(hello) 파라미터(String)
execution(public String hello.aop.member.MemberServiceImpl.hello(String))

//반환타입(*) 메서드이름(*) 파라미터(..)
//파라미터 .. 은 파라미터 타입과 파라미터 수가 상관없다는 뜻이다.
execution(* *(..))
    
//반환타입(*) 메서드이름(hello) 파라미터(..)
execution(* hello(..))
    
//반환타입(*) 메서드이름(*el*) 파라미터(..)
//* 으로 패턴 지정 가능
execution(* *el*(..))
    
//반환타입(*) 선언타입(hello ~ Impl).메서드이름(hello) 파라미터(..)
execution(* hello.aop.member.MemberServiceImpl.hello(..))
    
//반환타입(*) 선언타입(hello ~ *).메서드이름(*) 파라미터(..)
execution(* hello.aop.member.*.*(..))
    
//반환타입(*) 선언타입(hello ~..*).메서드이름(*) 파라미터(..)
//패키지에서 ..은 해당 패키지와 그 하위 패키지도 포함한다.
execution(* hello.aop.member..*.*(..))
    
//부모타입을 선언해도 자식 타입은 자동 매칭된다.
//단, 자식 타입에 있는 메서드가 부모 타입에 있어야지 매칭된다.
//자식 타입에만 있는 메서드는 매칭 실패
execution(* hello.aop.member.MemberServiceImpl.*(..))
execution(* hello.aop.member.MemberService.*(..))
    
//반환타입(*) 메서드이름(*) 파라미터(String) 
execution(* *(String))
    
//반환타입(*) 메서드이름(*) 파라미터()
//파라미터가 없어야 함
execution(* *())
    
//반환타입(*) 메서드이름(*) 파라미터(*)
//모든 파라미터 허용. 단, 하나의 파라미터만 있어야 함.
execution(* *(*))
    
//반환타입(*) 메서드이름(*) 파라미터(..)
//모든 파라미터 허용. 여러개의 파라미터가 있어도 모두 매칭.
execution(* *(..))
    
//반환타입(*) 메서드이름(*) 파라미터(String, ..)
//파라미터가 String 타입으로 시작만 하면 모두 매칭
execution(* *(String, ..))





📒 within

  • execution에서 타입 부분(패키지)만 사용한다고 생각하면 된다.
  • execution과 다른점은 부모 타입을 지정해도 자식 타입은 매칭이 안된다는 점이다.

📌 사용예시

within(hello.aop.member.MemberServiceImpl)
within(hello.aop.member.*Service*)
within(hello.aop..*)





📒 args

  • execution의 파라미터 부분과 같다.
  • 단독으로 사용되기보다는 파라미터 바인딩에 주로 사용된다.
  • execution은 파라미터 타입이 정확하게 매칭되어야 하지만, args는 부모 타입도 허용한다.
    • execution(* *(String)) 매칭 성공
    • execution(* *(java.io.Serializable) 매칭 실패
    • args(String) 매칭 성공
    • args(java.io.Serializable) 매칭 성공

📌 사용예시

args(String)
args(Object)
args()
args(..)
args(*)
args(String, ..)
args(java.io.Serializable)





📒 @target, @within

  • 클래스 애노테이션으로 AOP 적용 여부 판단
  • 단독으로 사용되기보다는 파라미터 바인딩에서 함께 사용된다.
  • @target@within의 차이
    • @target: 부모 클래스의 모든 매서드에 어드바이스 적용
    • @within: 자기 자신의 클래스에 정의된 메서드에만 어드바이스 적용

📌 사용예시

//execution으로 적용 대상을 줄인 뒤, 애노테이션이 있는 메소드를 매칭
execution(* hello.aop..*(..)) && @target(hello.aop.member.annotation.ClassAop)
execution(* hello.aop..*(..)) && @within(hello.aop.member.annotation.ClassAop)





📒 @annotation, @args

  • @annotation: 메서드 애노테이션으로 조인 포인트 매칭

  • @args: 전달된 실제 인수의 런타임 타입이 주어진 타입의 애노테이션이 갖는 조인 포인트


📌 사용예시

@annotation(hello.aop.member.annotation.MethodAop)

//전달된 인수의 런타임 타입에 @Check 애노테이션이 있는 경우에 매칭
@args(test.Check)





📒 bean

  • 스프링 전용 포인트컷 지시자, 빈의 이름으로 지정
  • *과 같은 패턴 사용 가능

📌 사용예시

//빈의 이름이 orderService, *Repository인 메서드에 AOP 적용
bean(orderService) || bean(*Repository)





📒 매개변수 전달

  • this, target, args,@target, @within, @annotation, @args을 이용해 어드바이스에 매개변수를 전달할수 있다.

📌 사용예시

  • 아래 코드는 다음과 같은 메서드가 축약된 모양이다.
@Before("allMember() && args(arg,..)")
public void logArgs(JoinPoint joinPoint, String arg) {
    log.info("[logArgs]{}, arg={}", joinPoint.getSignature(), arg);
}

@Pointcut("execution(* hello.aop.member..*.*(..))")
private void allMember() {}

@Around("allMember()")
public Object logArgs1(ProceedingJoinPoint joinPoint) throws Throwable {
    Object arg1 = joinPoint.getArgs()[0]; //joinPoint에서 매개변수를 꺼낼 수 있다.
    ...

@Before("allMember() && args(arg,..)")
public void logArgs3(String arg) { //매개변수 타입을 주의해야한다.

@Before("allMember() && this(obj)")
public void thisArgs(MemberService obj) { //프록시 객체를 전달 받음

@Before("allMember() && target(obj)")
public void targetArgs(MemberService obj) { //실제 대상 객체를 전달 받음

@Before("allMember() && @target(annotation)")
public void atTarget(ClassAop annotation) { //클래스타입의 애노테이션을 전달 받음

@Before("allMember() && @within(annotation)")
public void atWithin(ClassAop annotation) { //클래스타입의 애노테이션을 전달 받음

@Before("allMember() && @annotation(annotation)")
public void atAnnotation(MethodAop annotation) { //메서드의 애노테이션을 전달 받음

인프런의 '스프링 핵심 원리 고급편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요.

profile
I Think So!
post-custom-banner

0개의 댓글