어드바이스는 기본적으로 순서를 보장하지 않는다.
순서를 지정하고 싶으면 @Aspect
적용 단위로 org.springframework.core.annotation.@Order
애너테이션을 적용해야 한다.
어드바이스 단위가 아니라 클래스 단위로 적용할 수 있다.
하나의 애스펙트에 여러 어드바이스가 존재하면 순서를 보장 받을 수 없다.
애스펙트를 별도의 클래스로 분리해야 한다.
조인 포인트 실행 이전에 실행한다.
타겟 메서드가 실행되기 전에 처리해야할 필요가 있는 부가 기능을 호출하기 전에 공통 기능을 실행한다.
Before Advice 를 구현한 메서드는 일반적으로 리턴타입이 void다.
리턴 값을 갖더라도 실제 Advice 적용 과정에 아무 영향이 없다.
주의점으로 메서드에서 예외를 발생시킬 경우 대상 객체의 메서드가 호출되지 않게 된다는 점이 있다.
@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);
}
메서드 실행이 정상적으로 반환될 때 실행된다.
returning 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 한다.
returning 절에 지정된 타입의 값을 반환하는 메서드만 대상을 실행한다.
메서드가 예외를 던지는 경우에 실행한다.
메서드를 실행하는 도중 예외가 발생한 경우 공통 기능을 실행한다.
@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());
}
메서드 실행이 예외를 던져서 종료될 때 실행한다.
throwing 속성에 사용된 이름은 어드바이스 메서드의 매개변수 이름과 일치해야 한다.
throwing 절에 지정된 타입과 맞는 예외를 대상으로 실행한다.
조인 포인트의 동작(정상 또는 예외)과는 상관없이 실행한다.
메서드 실행 후 공통 기능을 실행한다.
일반적으로 리소스를 해제하는데 사용한다.
메서드 호출 전후에 수행하며 가장 강력한 어드바이스다.
메서드 실행 전 & 후, 예외 발생 시점에 공통 기능을 실행한다.
가장 강력한 어드바이스다.
try ~ catch ~ finally
가 들어가는 구문 처리가 가능하다.어드바이스의 첫 번째 파라미터는 ProceedingJoinPoint를 사용해야 한다.
proceed()
를 통해 대상을 실행한다.
proceed()
를 여러번 실행할 수 있다.
가장 강력한 어드바이스이며 대부분의 기능을 제공하지만 타겟 등 고려해야할 사항이 있을 때 정상적으로 작동이 되지 않는 경우가 있다.
@Before, @After와 같은 어드바이스는 기능은 적지만 원하는대로 작동되고 코드도 단순하다.
각 애너테이션만 봐도 타겟 실행 전에 어떤 일을 하는지 명확하게 알 수 있다.
좋은 설계는 @Around만 사용해서 모두 해결하는 것보다는 제약을 가지더라도 실수를 미연에 방지하는 것이다.
제약을 두면 문제 자체가 발생하지 않게 하며, 역할이 명확해진다.