Delivery 프로젝트에 주문 관련 로직을 담당하는 OrderService 클래스가 있습니다.
OrderService에서 제공하는 대표적인 메서드는 사용자에 따라 아래의 내용처럼 기능을 제공합니다.
User (소비자)
- 주문 요청
Owner (식당 주인)
- 주문 받기
- 주문 거절
Rider (배달원)
- 주문 배달 받기
- 주문 배달 완료
각각의 메서드는 Order Entity의 상태 값을 변경시켜줍니다.
ORDER_REQUEST, ORDER_APPROVAL, IN_DELIVERY, DELIVERY_COMPLETE, ORDER_CANCEL, ORDER_REFUSED
저는 실시간으로 상태 값을 보여주고 또한 알림의 목적으로 Firestore를 도입하기로 했습니다.
아래 코드는 Firestore에 Order를 저장하는 핵심 코드입니다. OrderService에 있는 메서드마다 아래의 메서드를 호출해 기능을 구현하였습니다.
private void saveOrderToFirestore(String collectionName, Order order) {
OrderDto orderDto = OrderDto.builder()
.id(order.getId())
.status(order.getOrderStatus())
.address(order.getAddress())
.build();
firestoreUtil.insertData(collectionName,
getOrderDocumentName(order.getId()), orderDto);
}
기능은 구현했지만 조금 아쉬웠던 부분이 OrderService가 Firestore를 의존하는 것과 모든 메서드에 saveOrderToFirestore()를 호출하는 게 지저분하다는 느낌을 받아 AOP로 분리하기로 했습니다.
SaveOrderToFirestoreForRestaurant
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SaveOrderToFirestoreForRestaurant {
}
SaveOrderToFirestoreForUser
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SaveOrderToFirestoreForUser {
}
OrderAspect
@Aspect
@Component
@RequiredArgsConstructor
public class OrderAspect {
private final FirestoreUtil firestoreUtil;
@Around("@annotation(setung.delivery.domain.order.aop.SaveOrderToFirestoreForRestaurant)")
public Object saveOrderToFirestoreForRestaurant(ProceedingJoinPoint joinPoint) throws Throwable {
Order order = (Order) joinPoint.proceed();
String collectionName = "restaurant_" + order.getRestaurant().getId();
saveOrderToFirestore(collectionName, order);
return order;
}
@Around("@annotation(setung.delivery.domain.order.aop.SaveOrderToFirestoreForUser)")
public Object saveOrderToFirestoreForUser(ProceedingJoinPoint joinPoint) throws Throwable {
Order order = (Order) joinPoint.proceed();
String collectionName = "user_" + order.getUser().getId();
saveOrderToFirestore(collectionName, order);
return order;
}
private void saveOrderToFirestore(String collectionName, Order order) {
OrderDto orderDto = OrderDto.builder()
.id(order.getId())
.status(order.getOrderStatus())
.address(order.getAddress())
.build();
firestoreUtil.insertData(collectionName,
getOrderDocumentName(order.getId()), orderDto);
}
private String getOrderDocumentName(long orderId) {
return "order_" + orderId;
}
}
간단하게 설명하자면 @Aspect로 선언한 클래스는 런타임 중에 Advisor를 생성해 빈 후처리 기를 통해 부가 로직을 수행하는 프록시를 만들게 됩니다. Firebase에 저장 로직이 수행될 메서드를 선별하는 포인트컷을 어노테이션으로 만들었고 OrderService의 메서드에 각각 해당 어노테이션을 붙여줌으로 AOP를 구현하였습니다.
'project > Delivery' 카테고리의 다른 글
[Delivery] 여러 명의 Rider가 동시에 동일한 주문 배달을 접수할 때 이슈 (0) | 2022.01.07 |
---|---|
[Delivery] Redis에 session 저장하기 (0) | 2021.12.31 |
[Delivery] 프로젝트 구조 (0) | 2021.12.28 |
댓글