본 게시물은 스스로의 공부를 위한 글입니다.
잘못된 내용이 있으면 댓글로 알려주세요!
implementation 'org.springframework.boot:spring-boot-starter-aop'
@Slf4j
@Aspect
public class AspectV1 {
@Around("execution(* hello.aop.order..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Around
로 포인트컷 설정joinPoint.proceed()
로 타겟 호출@Slf4j
@Aspect
public class AspectV3 {
@Pointcut("execution(* hello.aop.order..*(..))")
private void allOrder(){}
@Pointcut("execution(* *..*Service.*(..))")
private void allService(){}
@Around("allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log1] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
@Around("allOrder() && allService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log2] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
포인트컷을 다른 메서드로 분리 후 @Around( {메소드명} )
으로 참조할 수 있다.
포인트컷 조합은 &&
, ||
, !
이 가능하다.
public class Pointcuts {
@Pointcut("execution(* hello.aop.order..*(..))")
public void allOrder(){}
@Pointcut("execution(* *..*Service.*(..))")
public void allService(){}
@Pointcut("allOrder() && allService()")
public void orderAndService(){}
}
@Slf4j
@Aspect
public class AspectV4Pointcut {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log1] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log2] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Around
에 포인트컷 패지지명+메서드명을 써주면 된다.public
임을 주의@Slf4j
public class AspectV5Order {
@Aspect
@Order(2)
public static class LogAspect {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Aspect
@Order(1)
public static class TxAspect {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log2] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
}
@Order()
로 어드바이스 실행 순서를 지정할 수 있다.@Slf4j
@Aspect
public class AspectV6Advice {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[Around] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
@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("[AfterReturning] {} 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);
}
@After(value="hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint){
log.info("[after] {}", joinPoint.getSignature());
}
}
@Around
: 메서드 호출 전후에 수행, 조인 포인트 실행 여부, 반환 값 변환, 예외 변환 등 가능.proceed()
를 해야 다음 타겟이 실행된다. 여러번 호출도 가능@Before
: 조인 포인트 실행 이전에 실행@AfterReturning
: 조인 포인트가 정상 완료후 실행returning
속성에 사용된이름은 매개변수 이름과 일치해야 한다.@AfterThrowing
: 메서드가 예외를 던지는 경우 실행throwing
속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 한다.throw e
가 실행된다.@After
: 조인 포인트가 정상 또는 예외에 관계없이 실행(finally)@Around
만 있으면 모든 어드바이스 처리가 가능하다.@Around
는 항상 joinPoint.proceed()
를 호출해야 하므로 개발자가 실수할 여지가 있다.@Before
라는 애노테이션을 보는 순간 개발자의 의도를 쉽게 파악할 수 있지만, @Around
는 의도를 해석해야 한다.인프런의 '스프링 핵심 원리 고급편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요.