https://www.baeldung.com/spring-events

 

  • ``kt ApplicationEventPublisher::publishEvent``로 pub 하고
  • ``kt @EventListener``로 event 받아 처리하면 된다.
  • 단 여기서 주의해야 할점! listener가 이벤트를 수신하는 것이 왠지 비동기로 이루어질 것 같지만, 기본적으로 동기식이다!
    • 한 스레드가 pub한 다음, 해당 이벤트를 처리해야 하는 EventListener들을 돌면서 동기식으로 직접 리스너를 수행한다.
    • By default, the listener is invoked synchronously. However, we can easily make it asynchronous by adding an @Async annotation. We just need to remember to enable Async support in the application.

 

Event와 순환 참조 문제

  • Event를 사용하면 의존성을 끊을 수 있지만, 이렇게 의존성을 끊고 나서 반대방향 참조를 하게 되면 아래와 같은 에러를 마주칠 수 있다.
22:10:41.056 [WebSocketClient-SecureIO-2] ERROR o.s.w.s.a.s.StandardWebSocketHandlerAdapter - Closing session due to exception for StandardWebSocketSession[id=b85eba15-6fc8-6b1f-1c6d-bb93a2ccb1e7, uri=null]
org.springframework.beans.factory.BeanCreationNotAllowedException:
    Error creating bean with name 'myContainer': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)

 

  • 상황?
    • 종료 시, Listener가 Publisher를 참조하고 있으므로, Listener bean이 먼저 destroy 된다.
    • Publisher가 Event를 publish하면, 이벤트를 수신할 bean을 가져오게 되는데, 이 때 최종적으로 `` DefaultSingletonBeanRegistry.getSingleton``를 사용하여 가져오게 된다. 이 메서드는 싱글턴을 반환하는데 없으면 생성 시도한다.
    • Listener는 이미 destroy 되었으므로 생성 시도할텐데, shutdown으로 destruction phase에 진입했기 때문에 새로운 빈을 생성할 수 없다. 따라서 에러 발생하는 것.
/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName, ...

 

  • 해결?
    • 무시하거나, (어차피 종료 시에만 뜬다.)
    • try-catch 처리하거나,
    • application이 종료될 때, shutdown hook을 이용해서 flag 변수를 set하고 이를 체크하는 식으로 동작하거나. (✓)

 

 

도메인 모델에서 이벤트 직접 발행

https://namjug-kim.github.io/2020/03/24/spring-ddd-domain-event.html  

https://www.baeldung.com/spring-data-ddd