Java/Spring Boot

@TransactionalEventListener

amungstudy 2024. 7. 1. 15:42

@transactionalEventListener 가

어떻게 이벤트를 인식하여 리스너를 실행하는지 알아보겠습니다.

 

Spring에서의 Spring event의 실행 단계 : 

  1. 생성 주체에서 이벤트를 발생하면 이벤트 디스패처에게 전달
  2. 이벤트 디스패처가 이벤트 핸들러를 연결
  3. 이벤트 핸들러에서 이벤트에 담긴 데이터를 통해 원하는 기능을 실행

이번에 사용한 @TransactionalEventListener 는 적용할 메서드의 매개변수에 이벤트 객체를 정의해주면 지정한 이벤트가 발생했을 때 수신해서 처리할 수 있습니다. (이 점은@EventListener 와 동일)

또한 이벤트 발행자의 트랜잭션을 기준으로 이벤트 실행 시점을 조절할 때 사용할 수 있습니다.

option :

  • AFTER_COMMIT (default) : 트랜잭션이 성공적으로 commit되었을 때 이벤트 실행
  • AFTER_ROLLBACK : 트랜잭션이 rollback 되었을 때 이벤트 실행
  • AFTER_COMPLETION : 트랜잭션이 마무리 되었을 때(commit or rollback) 이벤트 실행
  • BEFORE_COMMIT : 트랜잭션의 커밋 전에 이벤트 실행

만약 리스너 코드를 아래와 같이 정의하게 되면

  @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void propagate(ScheduledEvent event){
        log.info("RECEIVED EVENT!!!,event = {}",event);
        log.info(TcpMessageCode.RECEIVED_TRANSACTIONAL_EVENT.getMessage());

        nettyService.sendMessage(event.getMemberIdList());
    }

정의해준 ScheduledEvent 객체를 이벤트 발행 시 같이 넘겨주어야 합니다.

매개변수가 일치하지 않으면 이벤트 디스패처가 핸들러를 연결할 수 없겠죠.

 @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
...

applicationEventPublisher.publishEvent(new ScheduledEvent(strings)); // 이벤트 리스닝 발동 o 
applicationEventPublisher.publishEvent("event"); // 이벤트 리스닝 발동 x

 

Spring Event

Spring에는 이벤트를 발생시키고 처리하기 위한 인터페이스를 제공하고 옵저버 패턴의 구현체인 Functional Interface ApplicationEventPublisher 를 제공합니다.

이벤트를 발생시키기 위해 사용할 때는 ApplicationEventPublisher 는 이미 Bean으로 등록되어있기 때문에 Bean을 주입받아 사용합니다.

Spring Event의 특징

  • 장점 - 각 모듈의 결합도를 낮추고 응집도를 높여주는 효과가 있습니다.
  • 단점 - 코드량과 애플리케이션의 복잡도가 높아집니다

이벤트 핸들러는 Spring 4.2 이전에는 ApplicationListener<E> 클래스를 상속받아야 했습니다.

@Slf4j
@Component
@RequiredArgsConstructor
// ApplicationReadyEvent(스프링 컨테이너가 모두 띄워졌을 때 발생하는 이벤트)를 받는 리스너 클래스
public class NettyStartupTask implements ApplicationListener<ApplicationReadyEvent> {

    private final NettyServerSocket nettyServerSocket;

    @Override
    public void onApplicationEvent( ApplicationReadyEvent event ) {

        // 실행할 로직
    }
}

 

하지만 이후부터는 이벤트 발생 시 처리하고 싶은 동작을 메서드에 정의하고, 해당 메서드에 어노테이션로 사용할 수 있습니다. (단, 메서드를 정의한 클래스는 Bean으로 등록되어야 합니다)

 

@EventListener

: 이벤트 핸들러를 구현하기 위해 사용하는 어노테이션입니다.

이 어노테이션을 사용하면 이벤트 리스너로 등록이 되고, 매개변수에 이벤트 객체를 정의하면 해당 이벤트가 발생했을 때 수신해서 처리할 수 있습니다.

그리고 TransactionalEventListener 와 달리 이벤트가 발생하자마자 실행됩니다.

사용 예시)

 @EventListener
    public void listener(String msg){
        log.info("MSG : {}",msg);
    }
 @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    
...
eventPublisher.publishEvent("deleteMember event");
... 다른 로직 실행

출력결과 : MSG : deleteMember event … 다른 로직 실행