여기까지 하고 나면 남은건 그냥 문법 공부라고 해도 된다.
스프링 어드바이스 애너테이션은 종류가 몇가지 더 있음.
@Around
가장 자주 사용됨. 범용성이 가장 높음. 메서드 호출 전 후에 수행. 조인포인트 실행여부를 선택하거나, 반환값이나 예외를 후킹해서 변환하는 등이 가능.
그럼 아래 애너테이션들은 언제 사용되는거? 그냥 가독성때문에 나눠놓은건가?
@Before
@AfterReturning
@After Throwing
@After
finally 문같은 느낌.하나씩 만들어보자.
package hello.aop.order.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Slf4j
@Aspect
public class AspectV6Advise {
@Around("hello.aop.order.aop.Pointcuts.allOrderAndService()")
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());
}
}
//ProceedingJoinPoint 객체는 오직 @Around에서만 사용가능하다.
//만약 @Before를 빈으로 등록했다면, 메서드의 실행 여부는 AOP에서는 컨트롤이 안됨. 그냥 자동으로 실행된다.
@Before("hello.aop.order.aop.Pointcuts.allOrderAndService()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
log.info("[before] {}", joinPoint.getSignature());
}
}
@Before 부터 하나씩 해볼건데, 이 친구들이 @Around 와 어떤차별점을 가지는가. 이게 왜 필요한가는 이걸 생각하면 된다.
⚠️ 왜 @Around 말고도 다른 어드바이스가 있을까?
@Around 를 사용하면 개발자가 메서드의 실행 여부까지 컨트롤 할 수 있다. 그래서 ProceedingJoinPoint 객체에서 proceed() 를 직접 호출해줘야 함. 호출 안하면 체인이 끊긴다. (까먹기 쉽다.)
이렇게 까지 신경쓰기 싫다 그러면 이제 간단한 어드바이스들을 사용하면 된다. 이 친구들은 특정 시점에 프록시로 호출되기만 하고 타겟 메서드의 실행 흐름 제어까지는 하지 않기 때문에 간단하게 쓰기 좋음. 그 렇게 처리되기 위해서 @Around 와는 다르게 procedingJoinPoint 객체가 아니라 그냥 JoinPoint 객체가 주입된다.
물론 그것조차 안받아도 된다.
그리고 이 친구들은 AOP로직의 의도가 애너테이션 이름에 잘 묻어난다. 즉 가독성이 좋다.