NextStep/DDD 세레나데

마지막 주차 - 도메인 event

백엔드 개발자 2025. 2. 25. 20:54

에릭에반스의 책에서는 도메인 이벤트는 등장하지 않는다.

반버논님의 도메인 주도 설계에서 처음 등장한다.

 

 

 

 

강한 결합의 단점

 

결합도를 낮추기 위한 선택지로 이벤트를 많이 사용한다.

(메세지를 주고받는 방법중 하나이다.)

함수를 콜할지, 이벤트방식으로 전달할지의 차이.

 

느슨한 결합을 맹목적으로 따라서 이벤트로 다 만드는 경우가 있는데, 오히려 설계가 복잡해진다.

구분해서 쓰자.

 

도메인 이벤트

도메인 전문가가 관심을 가질만한 사건

도메인 모델의 상태가 변경되었다는 것을 의미. 

~할때, ~이면 등의 상태를 도메인 이벤트로 구현해볼 수 있다.

 

 

가장 간단한 것은 자바의 옵저버 인터페이스를 상속받아서 구현하는 것이다.

 

 

 

이벤트 처리의 방식

응답을 받아서 어떤 행위를 해야하면 동기식이 제일 좋다.

 

이벤트의 처리결과를 기다릴 필요가 없다면 비동기 방식이 좋을 수 있다.

 

Spring Events

스프링 4 이후로는 인터페이스 방식에서 어노테이션 방식으로 업그레이드 되었다.

 

 

만약 또다른 이벤트를 추가해야 되는 요구사항이 늘어난다면?

 

 

 

강결합 상태.

3개중 하나의 sender에 성능적 저하나 장애발생시

고수준 모듈이 저수준 모듈에 영향을 받는다.

 

dip 그리고 도메인 이벤트가 그 해결방법이 될 수 있는 것.

 

ApplicationEventPublisher를 주입받는다.

publishEvent를 이용.

 

 

그렇다면 핸들러는 어떻게?

 

 

 

이벤트 핸들러는

@EventListener , event 파라미터 + 컴포넌트 등록이 필요하다

 

강결합을 이벤트로 제거함으로써 불필요한 import를 제거할 수 있는 효과가 있었다.

그리고 이벤트가 추가되도 따로 클래스만 추가하면 비즈니스로직을 안건드려도 되는 이점이 있다.

 

테스트는 어떻게?

가장 간단한건 fakeSender를 component로 만듬.

 

스프링 5.2까지의 테스트 방식이었다.

 

 

 

5.3부터는 @RecordApplicationEvents

 

 

동작자체는 fake 객체와 동일하나, 어노테이션으로도 동일하게 활용할 수 있도록 만들어줬다는 얘기.

기본적인 스프링 이벤트도 수신을하니 Joined라는 타입을 지정해줬다.

 

e2e 테스트시 결과가 이벤트 발행이면

SpringBoot로

 

그게 아니라 서비스 테스트할때는 stubbing해서 테스트하지는 않으신다고 한다.

 

 

로직 처리하다가 핸들러쪽에서 예외가 발생했다면?

전체코드가 롤백된다.

현재는 Transactional로 묶여있기 때문에.

이러면 비동기 이벤트방식은 아니게된다.

 

트랜잭션 범위안에 안묶이는 방법

1.@Async를 하는 것. + SpringBOotApplication에 @EnableAsync

 

 

 

2. TransactionalEventListener

실제 이벤트를 언제 수신할지를 트랜잭션의 주기와 관련해서 연결지어줄 수 있다.

트랜잭션이 커밋되기 전, 후, 롤백되기 전 후 등등

 

기본 설정값은 트랜잭션이 커밋된 후 이벤트 핸들링 로직이 수행됨.

 

예외는 발생을 하나, 테스트는 성공한다. 롤백이 되지는 않았다.

 

 

 

비즈니스로직에 따라 다르다.

트랜잭션 어노테이션을 붙일정도면

 

메세지 콜방식은 어떨지 먼저 고민필요

@EventListener 

 

 

 

얘는 더티체킹이 될까 안될까

값이 변경되지는 않았다.

트랜잭션 eventlistener는 after 커밋이 기본값.

종료된 트랜잭션이 존재하는 상태. 

그래서 기본은 트랜잭션이 있으면 그걸 사용하는 옵션인데

종료된 트랜잭션을 사용하고 있었던 상태라서 값이 안변했다.

 

그래서 Transactional(propagation = Propagation.REQUIRES_NEW)로

트랜잭션을 새로 생성하도록 한다.

 

 

 

 

이러면 값이 변경이 되지 않는다.

트랜잭션 동기화 매니저에서 아직 커넥션을 반납하지 않아서 예외가 발생함
required라 Event를 처리하는 쪽까지 끝나야 반납해서

 

 

@TransactionalEventListener

와 @Transactional을 같이 붙이도록 스프링에서 강제한 것 같다