본문 바로가기

spring

Entity를 저장할때 eventPublish 하기, TransactionalEventListener 추가 (1)

아래 방법의 문제

목표는 CustomEntity를 수정할때 publish하는 것인데, hibernate.integrator_provider를 추가할경우 CustomEntity 외의 다른 모든 Entity가 save될때에도 UpdateEventListener에서 이벤트가 발생한다.
그래서 UpdateEventListener에 조건문을 넣어 entity type을 확인하고 CustomEntity일때만 ApplicationListener로 전달하도록 했지만, 애초에 CustomEntity이 아니라면 UpdateEventListener에 이벤트가 전달될 필요가 없다.

CustomEntity일때에만 이벤트가 전달하게 (2)를 써야겠당

할 일

CustomEntity 가 수정될경우, CustomEntity와 CustomInfoEntity를 publish한다.

Listener를 사용해서 전체적으로 적용한다.

 

과정

1. CustomEventModel 추가

2. CustomEventModel를 publish하는 ApplicationEventPublisherAware 를 bean으로 추가

3. ApplicationEventPublisherAware의 publisher.publishEvent를 실행하는 PostCommitInsertEventListener, PostCommitUpdateEventListener, PostCommitDeleteEventListener 구현

4. 설정에 넣을 Integrator와 IntegratorProvider를 구현

5. bean을 사용하지 않을경우 spring.jpa.properties.hibernate.integrator_provider에 IntegratorProvider경로를 넣으면 되겠지만, 
ApplicationEventPublisherAware를 사용할거니까 LocalContainerEntityManagerFactoryBean에 설정하자.
EntityManagerFactoryBuilder로 bean을 생성할때 properties에 "hibernate.integrator_provider" to integratorProvider를 추가한다.

6. Component 를 생성하고 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = [CustomEventModel::class]) fun handle 구현한다.
handle에서 CustomEntity와 CustomInfoEntity를 가져오고 publish 하기.

7. event가 여러번 발생해도 한개씩 실행되므로 비동기로 돌린다

 

EventListener에서 이벤트를 바로 처리하지 못하고, ApplicationAware로 보냈던 이유

JpaProperties에 integratorProvider를 넣어야하는데, Repository를 주입받으려고 하면 bean의존성이 Cycle 구조가 돼서 에러가 발생한다.
event를 다른 리스너로 보내는게 더 편할것같아서 그렇게 햇당..

 

ApplicationListener<CustomEvent> 를 상속받아서 구현할경우 발생했던 문제

1. onPostUpdate 반복실행

오버라이드하는 함수 onPostUpdate(event: PostUpdateEvent)의 event.CustomEntity와 
ApplicationListener에서 Repository를 통해 새로 가져오는 CustomEntity가 같을경우 CustomEntity.update가 실행되기 때문에
onPostUpdate가 무한반복으로 실행된다.

2. ConcurrentModificationException

오버라이드하는 함수 onPostUpdate(event: PostUpdateEvent)의 event.CustomEntity와 
ApplicationListener에서 Repository를 통해 새로 가져오는 entity가 겹치지 않게 CustomInfoEntity만 가져오도록 실행할 경우 
eventHandle까지는 다 실행하지만, ConcurrentModificationException 발생하고 롤백한다.

 

ApplicationEventPublisherAware를 Bean으로 만들지 않을경우 문제

ApplicationEventPublisherAware.publisher를 주입받지 않지 않고 널포인트 익셉션 발생

 

PostUpdateEventListenerPostCommitUpdateEventListener 차이

org.hibernate.action.internal.EventUpdateAction.java 참고

PostXXXXEventListener

- 한 트렌젝션에서 CustomEntity와 CustomInfoEntity둘다 update할때, 각각을 업데이트 쿼리를 보내고 이벤트가 발생

PostCommitXXXXEventListener

- 둘다 업데이트하고 커밋하고 이벤트 발생
- requiresPostCommitHanding을 true로 설정해야함.