Spring AOP

신명철·2022년 7월 12일
0

Spring

목록 보기
3/3

AOP의 개념

  • Aspect : APP내 여러 곳에 흩어져있으며 Cross-Cutting 기능에 초점을 맞춘 코드/기능을 말한다. 여러 객체에 공통적으로 적용되는 관심 사항을 말한다.
  • JoinPoint : 프로그램이 실행 중일 때 발생하는 메서드 실행/생성자 호출/필드 값 수정과 같은 특수한 지점을 말한다.
  • Advice : 특정 JoinPoint의 Aspect에 의한 동작을 의미한다. 대상 객체의 JoinPoint에 Weaving되어서 동작할 수 있는 코드를 말한다.
  • PointCut : JoinPoint의 정규 표현식으로, JoinPoint가 PointCut과 일치할 때마다 해당 PointCut과 관련된 Advice가 실행된다.
  • Weaving : Aspect를 대상 객체에 연결시켜서 관점지향 객체로 만드는 과정을 말한다. 즉, Advice를 비즈니스 로직 코드에 삽입하는 것을 의미한다.

PointCut - Aspect 적용 위치 지정자

PointCut은 특정한 기준에 의해서 필터링된 JoinPoint를 말하는데, 수 많은 JoinPoint 중에서 특정 메서드에서 공통 기능을 수행시키기 위해 사용한다.

PointCut의 작성 방법

PointCut은 PCD(Pointcut Designator) 이라 하는 특정 지정자를 선언함으로써 시작한다. 예를 들어 다음과 같다.

  • @PointCut("execution(...)")
  • @PointCut("@annotation(...)")

기본적인 PCD

1. execution - 기본적인 PCD

  • [접근제한자패턴] 리턴타입패턴 [패키지&클래스패턴.] 메서드이름패턴 (파라미터패턴) [throws 예외 패턴]
  • 여기서 대괄호 []는 생략이 가능하다는 의미로 [접근제한자패턴], [리턴타입패턴], [throws 예외 패턴] 는 생략이 가능하다.
// 모든 패키지에 포함된 클래스 중에, 클래스 이름이 Service로 끝나는 클래스
@Pointcut("execution( * *..*Service.findUserId(..) )")

// 최소한의 필수 규칙들 → 리턴타입 메소드명(파라미터)
@Pointcut("execution( * findUserId(..) )")

// find로 시작하는 메소드
@Pointcut("execution( * find*(..) )")

2. within - 패키지와 클래스를 제한하는 PCD

  • execution과 비슷하지만, within은 메서드가 아니라 특정 타입에 속한 메서드를 PointCut으로 설정할 때 사용한다.
  • @PointCut("within(com.example.aspectj.LoginService)") 와 같은 경우, LoginService에 속하는 모든 메서드를 대상으로 PointCut이 설정된다.
  • @Pointcut("within(*..LoginService)") 는 모든 패키지에 존재하는 LoginService 이름을 가진 타입들의 메서드에 적용된다.

3. this & target - 생성된 Proxy에 대한 PCD

  • 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의 유무는 둘을 선택하는 기준이 되기도 한다.

4. args - 파라미터의 값이 궁금할 때

타깃의 메서드 호출에서 사용되는 파라미터의 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);
}
  • PointCut, Advice 어노테이션의 파라미터 명 name과 argsPCD, argsMethod의 파라미터 명name이 동일한 점에 주목하자

어노테이션과 PCD

@Controller, @Service, @Repository 처럼 어노테이션을 사용해서 AOP를 사용할 수 있다.

1. @target - 어노테이션이 부착된 클래스

@target PCD는 타깃 클래스에 포함된 어노테이션에 대한 조인 포인트를 사용한다

@PointCut("@target(org.springframework.stereotype.Service)")

위 코드는 @Service가 부착된 클래스의 모든 메서드를 대상으로 Advice가 적용된다.

2. @args - 대상 클래스가 파라미터로 사용되고 있는 클래스

@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, ...)")

3. @within - 특정 어노테이션을 통합 관리하는 PCD

@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

4. @annotation - 흔히 사용되는 PCD

@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)")

주입 시점 설정

1. @Before, @After

핵심 메서드의 호출 전/후에 실행된다. 매개변수를 JoinPoint를 사용한다.

2. @Around

핵심 메서드와 공통 메서드의 실행 시점을 자유롭게 설정할 수 있다. @Aroun 어노테이션은 매개 변수로 ProceedingJoinPoint를 사용한다. 해당 객체의 proceed()메서드는 핵심 메서드를 호출하는 기능이 있다. 따라서 try-catch 로 핵심 메서드를 선언하고 원하는 위치에 공통 메서드를 위치시킬 수 있다.

3. @AfterReturning

핵심 메서드가 종료되었을 때 조건없이 공통 메서드를 실행시킬 수 있다. @After는 method가 성공적으로 종료되든 종료되지 않든 작동하지만(e.g 예외 발생), @AfterReturning은 해당 핵심 메서드가 성공적으로 종료되었을 경우에만 작동한다.

4. @AfterThrowing

예외가 던져진 후에 작동한다.


참고

profile
내 머릿속 지우개

0개의 댓글