AOP Advice 종류

YH·2023년 3월 7일
0

어드바이스 종류

@Slf4j
@Aspect
public class AspectV6Advice {
    @Around("practice.aop.order.aop.Pointcuts.orderAndService()")
    //practice.aop.order 패키지와 하위 패키지 이면서 클래스 이름 패턴이 *Service
    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());
        }
    }

    @Before("practice.aop.order.aop.Pointcuts.orderAndService()")
    public void doBefore(JoinPoint joinpoint) {
        log.info("[before] {}", joinpoint.getSignature());
    }

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

    @AfterThrowing(value = "practice.aop.order.aop.Pointcuts.orderAndService()"
            , throwing = "ex")
    public void doThrowing(JoinPoint joinPoint, Exception ex) {
        log.info("[ex] {} message={}", ex);
    }

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

    • 메소드 실행 전후에 작업을 수행
    • 가장 강력한 어드바이스
      • 조인 포인트 실행 여부 선택 가능 -> joinPoint.proceed() 호출 여부
      • 전달 값 변환 : joinPoint.proceed(args[])
      • 반환 값 변환
      • 예외 변환
      • try - catch - finally 구문 처리 가능
    • 첫 번째 파라미터는 ProceedingJoinPoint를 사용해야 함
    • proceed()를 통해 대상을 실행
    • proceed()를 여러 번 실행 가능(재시도)
  2. @Before

    • 조인 포인트 실행 이전에 실행
    • @Around와 다르게 작업 흐름을 변경할 수 없음
    • @Around와 다르게 proceed()를 호출하지 않아도 자동으로 다음 타겟이 호출 됨
    • 예외가 발생하면 다음 타겟이 호출되지 않음
  3. @AfterReturning

    • 조인 포인트가 정상 완료 후 실행
    • returning 속성에 사용되는 이름은 어드바이스의 매개변수 명과 일치해야 함
    • returning 속성에 지정한 타입으로 반환하는 메소드만 실행 (부모 타입을 지정하면 모든 자식 타입도 실행 됨)
      • public void doReturn(JoinPoint joinPoint, Object result) 에서 Object 타입은 모든 타입을 받을 수 있으므로 다 실행되지만 특정 타입으로 지정하면 해당 타입의 리턴 타입을 가진 메소드만 실행 됨
    • @Around와 달리 반환되는 객체를 변경할 수 없음, 반환 객체를 조작은 가능
  4. @AfterThrowing

    • 메소드 실행이 예외를 던져서 종료될 때 실행
    • throwing 속성에 사용된 이름과 메소드 매개변수 명이 일치해야 함
    • 매개변수에 지정한 Exception 타입과 맞는 Exception을 대상으로 실행 함
  5. @After

    • 메소드 실행이 종료되면 실행 됨(Finally와 유사)
    • 정상 및 예외 반환 조건을 모두 처리 함
    • 일반적으로 리소스를 해제하는 데 사용 함

어드바이스 종류의 호출 순서

  • 호출 순서
    • @Around > @Before > @After > @AfterReturning > @AfterThrowing
  • 실행 순서와 리턴 순서는 반대임
  • 동일한 종류의 어드바이스가 2개 있으면 순서는 보장되지 않음 -> @Aspect를 분리 후 @Order 사용

어드바이스 종류가 여러 개인 이유

  • @Around만 있어도 모든 기능을 수행할 수 있으나 어드바이스를 나누어 사용하면,
    1. 실수 할 가능성이 낮아진다.
    2. 코드를 작성한 의도가 명확하게 파악됨
    3. 여러개로 나누어 제약을 둠으로써 실수를 방지하고 역할을 명확히 하여 좋은 설계를 할 수 있음
profile
하루하루 꾸준히 포기하지 말고

0개의 댓글