Spring AOP (3) : 어드바이스 종류

YUZE·2024년 11월 29일
0

Auction

목록 보기
4/5
post-thumbnail

어드바이스는 어느 시점어떤 기능을 의미한다.
따라서, 이번 포스팅에서는 어드바이스의 시점 지정에 대해 알아볼 것이다.
어드 바이스는 다양한 어노테이션을 AOP 실행 시점을 지정할 수 있다.


Adivce 어노테이션의 종류


어노테이션설명
@Around- 메서드 호출 전후에 수행
- 가장 강력한 어드바이스
- 조인 포인트 실행 여부 선택
- 반환 값 변환
- 예외 변환 등이 가능
@Before- 조인 포인트 실행 이전에 실행
@After- 조인 포인트가 정상 또는 예외에 관계없이 실행 (finally와 유사)
@AfterReturning- 조인 포인트가 정상 완료 후 실행
@AfterThrowing- 메서드가 예외를 던지는 경우 실행


@Around

 @Aspect
    @Order(2)
    public static class TxAspect {
        @Around("isyoudwn.aop.order.aop.PointCuts.orderAndService()")
        public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
            try {
		         // @Before
                log.info("[트랜잭션 시작] {}", joinPoint.getSignature());
                
                // 조인 포인트 실행
                Object result = joinPoint.proceed();
                
                // @AfterReturning
                log.info("[트랜잭션 커밋] {}", joinPoint.getSignature());
                return result;
            } catch (Exception e) {
		        // @AfterThrowing
                log.info("[트랜잭션 롤백] {}", joinPoint.getSignature());
                throw e;
            } finally {
			     // @After
                log.info("[리소스 릴리스] {}", joinPoint.getSignature());
            }
        }
    }
  • 메서드 실행 전 후에 작업을 수행한다
    • 조인 포인트의 실행 여부를 선택할 수 있다
    • 전달값(파라미터)을 변환할 수 있다
    • 메서드의 return이 아닌 다른 것을 반환할 수 있다
    • 예외를 변환해서 throw 할 수 있다
    • try-catch-finally 모두 들어가는 구문 처리 가능하다
  • ProceedingJoinPoint를 사용해야한다(규칙)
    • proceed()를 가지고있다
    • JoinPoint의 하위 타입이다
  • 조인포인트를 직접 실행해서 타겟을 실행해야한다
    • proceed()를 통해 대상을 실행한다
    • proceed()를 여러번 실행할 수 있다(재시도 기능 가능)

💡 Around 하나만 있어도, AOP의 모든 시점을 구현할 수 있다.
그러나, Target직접 실행해야 되는 단점이 있고, Advice의 내부 로직을 이해해야지만, 그 Advice가 어떤 시점에 실행되는지 알 수 있다.
따라서, 아래와 같이 시점을 특정하는 어노테이션이 존재한다.



@Before

조인 포인트 실행 전 Advice 실행

    // before은 로직 수행 후 joinpoint를 실행한다
    @Before("isyoudwn.aop.order.aop.PointCuts.orderAndService()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("[before] {}", joinPoint.getSignature());
    }
  • 메서드 종료시 자동으로 다음 타켓이 호출된다
  • 예외가 발생하면 다음 코드가 호출되지 않는다


@AfterReturning

메서드 실행 후 정상적으로 Return될 때 Advice 실행

 @AfterReturning(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()", returning = "result")
    public void doReturn(JoinPoint joinPoint, Object result) {
        log.info("[return] {} return = {}", joinPoint.getSignature(), result);
    }
  • value에 포인트 컷을 넣는다
  • returning속성에 사용된 이름과 파라미터를 동일한 이름으로 지정하면, 매칭되어서 파라미터에 return 값이 들어온다. 이때, 파라미터 타입은 메서드의 반환 타입과 동일해야 된다(부모 타입을 지정하면 모든 자식 타입은 인정된다)
  • return값이 매칭이 안되면 어드바이스 자체가 실행이 안된다
  • 메서드 자체에 반환하는 return 을 조작할 수 없다


@AfterThrowing

메서드 실행이 예외를 던져서 종료될 때 실행될 때 Advice 실행

    @AfterThrowing(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()", throwing = "ex")
    public void doReturn(JoinPoint joinPoint, Exception ex) {
        log.info("[ex] message = {}", ex.getMessage());
    }
  • throwing 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야한다
  • throwing 파라미터에 지정된 타입과 맞는 예외를 대상으로 실행한다(부모 타입을 지정하면, 모든 자식 타입은 인정된다)


@After

메서드 실행이 종료되면 Advice가 실행된다. (finally를 생각하면 된다)

  @After(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()")
    public void doAfter(JoinPoint joinPoint) {
        log.info("[after] {}", joinPoint.getSignature());
    }
  • 정상 및 예외 반환 조건을 모두 처리한다
  • 리소스를 해제 하는데 일반적으로 많이 사용한다


전체 코드

@Slf4j
@Aspect
public class AspectV6Advice {
    
    // before은 로직 수행 후 joinpoint를 실행한다
    @Before("isyoudwn.aop.order.aop.PointCuts.orderAndService()")
    public void doBefore(JoinPoint joinPoint) {
        log.info("[before] {}", joinPoint.getSignature());
    }

    @AfterReturning(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()", returning = "result")
    public void doReturn(JoinPoint joinPoint, Object result) {
        log.info("[return] {} return = {}", joinPoint.getSignature(), result);
    }

    @AfterThrowing(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()", throwing = "ex")
    public void doReturn(JoinPoint joinPoint, Exception ex) {
        log.info("[ex] message = {}", ex.getMessage());
    }

    @After(value = "isyoudwn.aop.order.aop.PointCuts.orderAndService()")
    public void doAfter(JoinPoint joinPoint) {
        log.info("[after] {}", joinPoint.getSignature());
    }
}


결과

Around를 사용하지 않고, 시점을 특정하는 어노테이션을 총동원해서 작성한 Advice 들의 실행 결과는 아래와 같다.

  • success
  • exception


동일한 조인 포인트에서 어드바이스 실행 순서


Aspect 안에 동일한 종류의 어드바이스가 2개이면 순서가 보장되지 않기 때문에, 이 경우에는 @Order을 사용해서 순서를 지정해주어야 한다!

profile
안녕하세요

0개의 댓글

관련 채용 정보