PointCut은 특정한 기준에 의해서 필터링된 JoinPoint를 말하는데, 수 많은 JoinPoint 중에서 특정 메서드에서 공통 기능을 수행시키기 위해 사용한다.
PointCut은 PCD
(Pointcut Designator) 이라 하는 특정 지정자를 선언함으로써 시작한다. 예를 들어 다음과 같다.
// 모든 패키지에 포함된 클래스 중에, 클래스 이름이 Service로 끝나는 클래스
@Pointcut("execution( * *..*Service.findUserId(..) )")
// 최소한의 필수 규칙들 → 리턴타입 메소드명(파라미터)
@Pointcut("execution( * findUserId(..) )")
// find로 시작하는 메소드
@Pointcut("execution( * find*(..) )")
execution
과 비슷하지만, within
은 메서드가 아니라 특정 타입에 속한 메서드를 PointCut으로 설정할 때 사용한다.@PointCut("within(com.example.aspectj.LoginService)")
와 같은 경우, LoginService에 속하는 모든 메서드를 대상으로 PointCut이 설정된다.@Pointcut("within(*..LoginService)")
는 모든 패키지에 존재하는 LoginService 이름을 가진 타입들의 메서드에 적용된다.this
: CGLib로 생성된 Proxy를 대상으로 설정target
: JDK Dynamic Proxy로 생성된 Proxy를 대상으로 설정JDK Dynamic Proxy
로 생성된 Proxy들은 target의 interface를 통해서 만들어진다. 즉, target object의 Proxy를 만들려면 target object 의 interface를 제공해야 하며 target 은 interface를 implements 해야만 한다.
반면 CGLib
로 생성된 Proxy들은 interface를 implements 하지 않는다. interface의 유무는 둘을 선택하는 기준이 되기도 한다.
타깃의 메서드 호출에서 사용되는 파라미터의 value가 필요하다면 args
를 사용하면 된다.
@Pointcut("within(*..LoginServiceImpl) && args(name)")
public void argsPCD(Object name) {
}
@Before("argsPCD(name)")
public void argsMethod(Object name) {
System.out.println("args : "+ name);
}
name
과 argsPCD, argsMethod의 파라미터 명name
이 동일한 점에 주목하자@Controller, @Service, @Repository 처럼 어노테이션을 사용해서 AOP를 사용할 수 있다.
@target
PCD는 타깃 클래스에 포함된 어노테이션에 대한 조인 포인트를 사용한다
@PointCut("@target(org.springframework.stereotype.Service)")
위 코드는 @Service
가 부착된 클래스의 모든 메서드를 대상으로 Advice가 적용된다.
@args
PCD는 런타임시 특정 타입의 클래스가 파라미터로 사용되고 있을 때,추적하기 위한 목적으로 사용되는 PCD다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Foo{}
@Foo
public class Bar {}
public class LoginService {
public void method(Bar bar) {
...
}
}
위 코드처럼 @Foo
어노테이션이 붙은 Class가 파라미터로 사용되는 메서드에 PointCut를 적용하고 싶다면 다음처럼 작성하면 된다.
@PointCut("@args(com.example.tutorial.Foo)")
@PointCut("@args(com.example.tutorial.Foo, ...)")
@within
은 클래스에 특정 어노테이션이 지정되어 있으면, 해당 클래스의 모든 메서드에 Advice를 적용한다.
@PointCut("@within(org.springframework.stereotype.Service)")
@PointCut("within(@org.springframework.stereotype.Service)")
@target
과 비슷해보이지만 차이점이 있다. 차이점은 다음 링크 참조
=> https://stackoverflow.com/questions/51124771/difference-between-target-and-within-spring-aop
@annotation
은 가장 많이 사용되고 있는 PCD라고 한다. 사용법은 다음과 같다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Foo{}
@Foo
public class Bar {}
public class LoginService {
public void method(Bar bar) {
...
}
}
@Pointcut("@annotation(com.example.tutorial.Foo)")
@Pointcut("@annotation(Foo)")
핵심 메서드의 호출 전/후에 실행된다. 매개변수를 JoinPoint를 사용한다.
핵심 메서드와 공통 메서드의 실행 시점을 자유롭게 설정할 수 있다. @Aroun
어노테이션은 매개 변수로 ProceedingJoinPoint
를 사용한다. 해당 객체의 proceed()
메서드는 핵심 메서드를 호출하는 기능이 있다. 따라서 try-catch
로 핵심 메서드를 선언하고 원하는 위치에 공통 메서드를 위치시킬 수 있다.
핵심 메서드가 종료되었을 때 조건없이 공통 메서드를 실행시킬 수 있다. @After
는 method가 성공적으로 종료되든 종료되지 않든 작동하지만(e.g 예외 발생), @AfterReturning
은 해당 핵심 메서드가 성공적으로 종료되었을 경우에만 작동한다.
예외가 던져진 후에 작동한다.