kongkong.note

[도메인 주도 개발 시작하기] 10. 이벤트 본문

DDD

[도메인 주도 개발 시작하기] 10. 이벤트

hyokong 2026. 1. 18. 19:15

이벤트

  • 바운디드 컨텍스트 간 강한 결합 제거 목적
  • 스프링에서 제공하는 ApplicationEventPublisher 활용

이벤트 구성 요소

이벤트 생성 주체(이벤트 발생) -> 이벤트 디스패처(이벤트 전달)-> 이벤트 핸들러(이벤트 처리)

이벤트 이름

과거시제를 사용. ex) ChangedEvent{}

이벤트 장점

서로 다른 도메인 로직이 섞이는 것을 방지, 의존성 제거


❌ 강결합 예시

// Tuition Context
public class TuitionService {

    private final ApprovalService approvalService; // 다른 컨텍스트 직접 의존 ❌

    public void approve(Long tuitionId) {
        TuitionApplication app = repo.findById(tuitionId);
        app.approve();

        approvalService.requestApproval(tuitionId); // 강결합
    }
}

✅ 이벤트 (동기)

  • Tuition Context – 이벤트 발행
public class TuitionApplication {

    public void approve() {
        this.status = APPROVED;
        DomainEvents.raise(new TuitionApprovedEvent(this.id));
    }
}
  • Approval Context – 이벤트 수신 (동기)
@Component
public class ApprovalEventListener {

    @EventListener
    public void handle(TuitionApprovedEvent event) {
        approvalService.createRequest(event.tuitionId());
    }
}

✅ 이벤트 (비동기)

  • Approval Context – 비동기 수신 : @Async
    • Tuition 트랜잭션과 분리
    • Approval 실패해도 Tuition 승인 유지
    • 확장성 좋음
@Async
@TransactionalEventListener(phase = AFTER_COMMIT)
public void handle(TuitionApprovedEvent event) {
    approvalService.createRequest(event.tuitionId());
}

이벤트 사용 주의사항

1️⃣ 절대 하면 안되는 것

  • 다른 컨텍스트 Aggregate 수정 금지
@EventListener
public void handle(TuitionApprovedEvent e) {
    tuitionRepository.save(...); // 다른 컨텍스트 Aggregate 수정 ❌
}

2️⃣ 트랜잭션 실패를 함께 고려 필요

  • @TransactionalEventListener(AFTER_COMMIT) 활용하여 트랜잭션 커밋 성공 후 핸들러 메서드 실행하도록 적용