package com.example.demo.order.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Slf4j
@Aspect
public class AspectV6Advice {

   @Around("com.example.demo.order.aop.Pointcuts.orderAndService()")
    //com.demo.order 패키지와 하위 패키지 이면서 클래스 이름이 *Service
    public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable{
        try{
            //@Before
            log.info("[트랜잭션 시작] {}",joinPoint.getSignature());
            Object result = joinPoint.proceed();
            //@AfterReturning
            //@After
            log.info("[트랜잭션 커밋] {}",joinPoint.getSignature());
            return result;
        }catch (Exception e){
            //@AfterThrowing
            log.info("[트랜잭션 롤백] {}",joinPoint.getSignature());
            throw e;
        }finally {

            log.info("[리소스 릴리즈] {}",joinPoint.getSignature());
        }
    }
    //기존에서 쓰던 ProceedingJoinPoint는 @Around에서만 사용하는 파라미터다. 여기서는 JoinPoint를 사용한다.
    //파라미터를 비워놔도 해당 포인트컷 내에서 코드가 실행된다. 무조건적으로 해당 위치에서 프로세스가 실행되기 전에 실행된다는 이야기.
    @Before("com.example.demo.order.aop.Pointcuts.orderAndService()")
    public void doBefore(JoinPoint joinPoint){
        log.info("[before] {} ",joinPoint.getSignature());
    }

    //@AfterReturning은 return한 값을 조작할 수 는 있으나, return 자체를 변경할 수는 없다.
    @AfterReturning(value = "com.example.demo.order.aop.Pointcuts.orderAndService()", returning = "result")
    public void doReturn(JoinPoint joinPoint,Object result){
        log.info("[return] {} return={} ",joinPoint.getSignature(),result);
    }
    //해당 포인트컷의 리턴타입이 무엇이냐에 따라서 여러 타입으로도 받을 수 있다.
    @AfterReturning(value = "com.example.demo.order.aop.Pointcuts.allOrder()", returning = "result")
    public void doReturn2(JoinPoint joinPoint,String result){
        log.info("[return2] {} return={} ",joinPoint.getSignature(),result);
    }

    @AfterThrowing(value = "com.example.demo.order.aop.Pointcuts.orderAndService()",throwing = "ex")
    public void doThrowing(JoinPoint joinPoint,Exception ex){
        log.info("[ex] {} message={} ",ex);
    }
    //@After는 finally 로직과 비슷하다고 보면 된다. 즉, 할수있는 것이 많이 없다.
    @After(value = "com.example.demo.order.aop.Pointcuts.orderAndService()")
    public void doAfter(JoinPoint joinPoint){
        log.info("[after] {} ",joinPoint.getSignature());
    }

}
  • @Before
    • 조인포인트를 실행하기 전 
    • @Around와 다르게 작업 흐름을 변경할 수 없다.
    • ProceedingJoinPoint.proceed()를 사용하지 않는다.
    • 메서드 종료 시 자동으로 다음 타겟이 호출된다.
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()",
returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
 log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
  • @AfterReturning
    • 메서드 실행이 정상적으로 반환될 때 실행 
    • returning 속성에 사용된 이름은 어드바이스 메서드의 매개변수 일므과 일치해야 한다.
    • returning 절에 지정된 타입의 값을 반환하는 메서드만 대상으로 실행한다.
    • @Around와 다르게 반환되는 객체를 변경할 수 는 없다. 반환 객체를 변경하려면 @Around를 사용해야 한다.하지만 조작할 수는 있다.
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()",
throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
 log.info("[ex] {} message={}", joinPoint.getSignature(), ex.getMessage());
}
  • AfterThrowing
    • 메서드 실행이 예외를 던져서 종료될 때 실행
    • throwing 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 한다.
    • throwing 절에 지정된 타입과 맞는 예외를 대상으로 실행한다.
  •  @After
    • 메서드 실행이 종료되면 실행된다.
    • 정상 및 예외 반환 조건을 모두 처리한다.
    • 일반적으로 리소스를 해제하는 데 사용한다.
  • @Around
    • 메서드의 실행주변에서 실행된다. 메서드 실행 전후에 작업을 수행한다.
    • 가장 강력한 어드바이스
      • 조인 포인트 실행여부 선택 
      • 전달 값 변환 : joinPoint.proceed(args[])
      • 반환 값 변환
      • 예외 변환
      • 트랜직션 처럼 try~catch~finally 모두 들어가는 구문 처리 가능
    • 어드바이스의 첫 번째 파라미터는 ProceedingJoinPoint를 사용해야 한다
    • proceed()를 통해 대상을 실행한다.
    • proceed()를 여러번 실행 할 수도 있음(재시도)

 

'Java > 스프링 AOP' 카테고리의 다른 글

스프링 AOP - execution(2)  (0) 2023.09.14
스프링 AOP - execution(1)  (0) 2023.09.12
Spring AOP - 포인트컷 분리  (0) 2023.09.07
Spring AOP 용어정리  (0) 2023.09.06
Spring AOP - 핵심기능, 부가기능 , 애스펙트  (0) 2023.09.05

+ Recent posts