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등이 사용되는 이유