카테고리 없음

[스프링 핵심원리 고급편] 스프링 AOP 구현

AOP를 사용할 때 아래 디펜던시 추가 필요 (spring JPA, spring data jpa등에는 이미 포함되어있음)

implementation 'org.springframework.boot:spring-boot-starter-aop' 

 

스프링의 AOP

스프링은 AspectJ의 껍데기(인터페이스)를 차용해서 사용함

실제로 AspectJ 프레임웍을 사용하는 것은 아님  

 

포인트컷 분리

 @Slf4j
 @Aspect
 public class AspectV2 {
  
      //hello.aop.order 패키지와 하위 패키지
      @Pointcut("execution(* hello.aop.order..*(..))") //pointcut expression 
      private void allOrder(){} //pointcut signature
     
     @Around("allOrder()")
      public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
          log.info("[log] {}", joinPoint.getSignature());
          return joinPoint.proceed();
      }

 

 

 

@Order(n)

- 어드바이스를 거는 순서

- Aspect단위로 걸림

- 클래스 분리 필요

 

 

 

어드바이스 종류

@Around : 메서드 호출 전후에 수행, 가장 강력한 어드바이스, 조인 포인트 실행 여부 선택, 반환 값 변환, 예외 변환 등이 가능

--여기서부터 로직을 알아서 실행해줌

@Before : 조인 포인트 실행 이전에 실행

@AfterReturning : 조인 포인트가 정상 완료후 실행 @AfterThrowing : 메서드가 예외를 던지는 경우 실행

@AfterThrowing : 메서드가 예외를 던지는 경우 실행

@After : 조인 포인트가 정상 또는 예외에 관계없이 실행(finally)

@Slf4j
@Aspect
public class AspectV6Advice {
   @Around("hello.aop.order.aop.Pointcuts.orderAndService()")
   public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
      try {
         //@Before
         log.info("[around][트랜잭션 시작] {}", joinPoint.getSignature()); 
         Object result = joinPoint.proceed();
              
         //@AfterReturning
         log.info("[around][트랜잭션 커밋] {}", joinPoint.getSignature());
         return result;
      } catch (Exception e) {
         //@AfterThrowing
         log.info("[around][트랜잭션 롤백] {}", joinPoint.getSignature());
         throw e;
      } finally {
         //@After
         log.info("[around][리소스 릴리즈] {}", joinPoint.getSignature()); }
      }

      @Before("hello.aop.order.aop.Pointcuts.orderAndService()")
      public void doBefore(JoinPoint joinPoint) {
          log.info("[before] {}", joinPoint.getSignature());
      }
      
      @AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
      public void doReturn(JoinPoint joinPoint, Object result) {
          log.info("[return] {} return={}", joinPoint.getSignature(), result);
      }
      
      @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());
      }
      
      @After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
      public void doAfter(JoinPoint joinPoint) {
          log.info("[after] {}", joinPoint.getSignature());
      }
}

@Around는 joinPoint.proceed()를 호출하지 않으면 버그가 발생함.

좋은 설계는 제약이 있는 것

--> Around 대신 Before, After등이 사용되는 이유