__이벤트 관련 구성요소__

이벤트 구성 요소

  1. 이벤트(Event)
    1. 도메인 모델의 상태 변화를 나타내는 사건
  1. 이벤트 생성 주체(Event Creator)
    1. 엔티티, 밸류, 도메인 서비스 등의 도메인 객체로, 도메인 로직을 수행해서
    1. 상태가 변경될 때 관련 이벤트를 발생시킴.
  1. 이벤트 디스패처(Event Dispatcher/Publisher)
    1. 이벤트 생성 주체가 발생시킨 이벤트를 적절한 이벤트 핸들러에게 전달하는 역할
    1. 이벤트의 생성과 처리를 동기 또는 비동기 방식으로 선택적으로 처리가능
  1. 이벤트 핸들러(Event Handler/Subscriber)
    1. 이벤트에 반응하여 특정 기능을 수행하는 구성요소
    1. 주문 취소됨 이벤트 를 받는 이벤트 핸들러의 경우
      1. 주문 취소 사실을 주문자에게 SMS 으로 전달이 가능하다.

이벤트예시

  1. 이벤트 의 구성 요소
    1. 이벤트 종류
    1. 이벤트 발생 시간
    1. 추가 데이터
    public class ShippingInfoChangedEvent {
        private String orderNumber;
        private long timestamp;
        private ShippingInfo newShippingInfo;
        // 생성자, getter...
    }
    • 일반적으로 이벤트는 Changed 라는 과거시제를 사용한다.
      • 이벤트가 과거에 발생한 것이기 때문에 과거를 기준으로 이벤트 이름을 사용한다고 합니다
  1. 이벤트의 발생 주체
    1. 이벤트를 발생시키는 주체는 Order 애그리거트와 같은 도메인 객체이다.
      public class Order {
          public void changeShippingInfo(ShippingInfo newShippingInfo) {
              verifyNotYetShipped();
              setShippingInfo(newShippingInfo);
              Events.raise(new ShippingInfoChangedEvent(number, newShippingInfo)); // 이벤트 핸들러 등록
          }
      }
      • 예를 들어 배송지 정보 변경 기능을 구현한 메소드는 다음과 같이 이벤트를 발생시킬 수 있음
  1. 이벤트 핸들러
    • ShippingInfoChangedEvent를 처리하는 핸들러는 이벤트를 받아 필요한 작업을 수행합니다.
      public class ShippingInfoChangedHandler {
          @EventListener(ShippingInfoChangedEvent.class)
          public void handle(ShippingInfoChangedEvent evt) {
              shippingInfoSynchronizer.sync(evt.getOrderNumber(), evt.getNewShippingInfo());
          }
      }
      • shippingInfoSynchronizer
        • 이름만 거창해 보이지 그냥 서비스를 수행의 역할을 하는 것 같다.

이벤트 핸들러 비동기 처리 방식

  • @EnableAsync 설정으로 스프링의 비동기 메서드 실행 기능을 활성화 가능함.
    • @Async 어노테이션이 붙은 메서드를 비동기적으로 실행이 가능하다.
    • 비동기 메서드는
@SpringBootApplication
@EnableAsync
public class AsyncMethodApplication {

  public static void main(String[] args) {
    SpringApplication.run(AsyncMethodApplication.class, args).close();
  }
@Service
public class AsyncService {

  @Async
  public CompletableFuture<String> processAsync() {
    // 비동기로 처리할 로직
    String result = doSomeHeavyLifting();
    return CompletableFuture.completedFuture(result);
  }

  private String doSomeHeavyLifting() {
    // 시간이 많이 걸리는 작업
    return "작업 완료";
  }
}
  • AsyncService #processAsync
    • 메서드는 비동기로 수행되며,
    • #doSomeHeavyLifting 는 작업을 별도의 스레드에서 처리함,
    • CompletableFuture.completedFuture
      • 작업 결과를 즉시 반환할 수 있음
      • 원래 비동기라 결과를 즉시 반환하기 어려움.
      • voidFuture 타입만 반환가능하다.

이벤트 용도

트리거로서의 이벤트

  • 도메인의 상태가 변경되는 경우
    • 후처리를 작업하기 위한 트리거로서의 이벤트로 활용이 가능
      • 주문 시스템에서 주문 취소 이벤트환불 처리를 위한 트리거로 사용가능
  • 주문 취소와 환불 처리
    • Order 클래스에서 주문 취소 시 OrderCanceledEvent를 발생
    • EventDispatcher가 이벤트를 감지하고 관련된 EventHandler에 전달합니다.
    • OrderCanceledEventHandler는 RefundService를 호출하여 환불 처리를 수행합니다.

서로 다른 시스템 간의 데이터 동기화로서의 이벤트

  • 배송지가 변경된 경우
    • 주문 도메인
      • 배송지 변경 이벤트 발생
      • 이벤트 핸들러
        • 외부 배송 서비스와 데이터를 동기화를 담당한다.

이벤트의 장점

  • 개요
    • 도메인 로직의 분리와 기능 확작성을 제공하는 중요한 방법론
    • 서로 다른 도메인 로직이 섞이는 것을 방지.
    • 시스템의 결합도를 낮출 수 있다.

도메인 로직의 분리

  • 주문 취소 로직에 환불 처리 로직을 직접 포함 X
  • 의존 제거@
  • 주문 취소 이벤트를 발생시켜 이벤트 핸들러가 환불 처리를 담당하도록 할 수 있음

    전통적인 방식

    public class Order {
      public void cancel(RefundService refundService) {
        verifyNotYetShipped();
        this.state = OrderState.CANCELED;
        this.refundStatus = State.REFUND_STARTED;
        try {
          refundService.refund(getPaymentId());
          this.refundStatus = State.REFUND_COMPLETED;
        } catch(Exception ex) {
          // 예외 처리 로직
        }
      }
    }

    이벤트 기반 방식

    public class Order {
      public void cancel() {
        verifyNotYetShipped();
        this.state = OrderState.CANCELED;
        Events.raise(new OrderCanceledEvent(number.getNumber()));
      }
    }
    • cancel 메서드는 주문 상태를 변경하고,
    • OrderCanceledEvent 를 발생시키는 역할만 수행함.
    • 환불 처리 로직은 이벤트 핸들러에서 담당한다.

출처

Getting Started | Creating Asynchronous Methods (spring.io)

Async (Spring Framework 6.1.3 API)

도메인 주도 개발


Uploaded by N2T