스프링/스프링 AOP
@Pointcut - 포인트컷 분리
chanhee01
2023. 9. 22. 14:36
AOP 동작을 위한 service, repository 코드
OrderRepository.class
@Slf4j
@Repository
public class OrderRepository {
public String save(String itemId) {
log.info("[orderRepository] 실행");
//저장 로직
if (itemId.equals("ex")) {
throw new IllegalStateException("예외 발생!");
}
return "ok";
}
}
OrderService.class
@Slf4j
@Service
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public void orderItem(String itemId) {
log.info("[orderService] 실행");
orderRepository.save(itemId);
}
}
AOP가 적용되는지 확인을 위한 Service와 Repository 코드이다. 진짜 간단하게 로그를 통해 어떤 것이 실행되는지만 적어놨다.
포인트컷 분리 전 - @Around에 경로
@Slf4j
@Aspect
public class AspectV1 {
@Around("execution(* hello.aop.order..*(..))") // 포인트컷
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); // joinPoint 시그니처 (메서드 뭐 호출되었는지)
return joinPoint.proceed();
}
}
이전에도 포스팅했지만 @Aspect 어노테이션을 활용하면 aop를 쉽게 적용할 수 있다.
포인트컷 분리 전 - @Poincut 사용
@Slf4j
@Aspect
public class AspectV2 {
// hello.aop.order 패키지와 하위 패키지
@Pointcut("execution(* hello.aop.order..*(..))") // 포인트컷
private void allOrder(){}
@Around("allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Around에 포인트컷의 경로를 넣는 것이 아니라 @Pointcut 어노테이션을 이용해서 거기에 경로를 설정할 수도 있다. @Around 어노테이션에는 allOrder()라는 메서드를 넣어주면 된다.
allOrder()의 코드 내용은 비워두고 반환 타입은 무조건 void여야 한다.
이렇게 하면 doLog2() 등 다른 aop가 있을 때 allOrder()를 넣어줘서 같은 포인트 컷을 넣어줄 수 있다.
물론 @Around와 @Poincut 어디에 경로를 넣든 결과는 똑같다.
하나의 포인트컷 표현식으로 여러 어드바이스에서 함께 사용할 수도 있으며 public으로 선언하면 다른 클래스에 있는 외부 어드바이스에서도 포인트컷을 함께 사용할 수도 있다.
Pointcut.class
package hello.aop.order.aop;
import org.aspectj.lang.annotation.Pointcut;
public class Pointcuts {
@Pointcut("execution(* hello.aop.order..*(..))")
public void allOrder(){}
@Pointcut("execution(* *..*Service.*(..))")
public void allService(){}
// 위 2개의 동시 조건 포인트컷
@Pointcut("allOrder() && allService()")
public void orderAndService(){}
}
포인트컷 클래스를 만들고 그 클래스의 경로를 입력하면 포인트컷을 외부에서 사용할 수 있다.
@Pointcut("hello.aop.order.aop.Pointcuts.allOrder()")
private void allOrder(){}
포인트컷의 경로.클래스이름.메서드 이름을 통해 포인트컷의 경로를 넣어줬다.