@EventListener

ddee·2026년 7월 13일

기본 개념

스프링은 애플리케이션 안에서 "이벤트를 발행(publish)하고, 그걸 구독(listen)하는" 구조를 지원. Observer패턴을 스프링이 대신 관리해주는 것.

// 1. 이벤트 정의
public class OrderCreatedEvent {
    private final Long orderId;
    // 생성자, getter...
}

// 2. 이벤트 발행
@Service
public class OrderService {
    private final ApplicationEventPublisher eventPublisher;

    public void createOrder(Order order) {
        // ... 주문 저장 로직
        eventPublisher.publishEvent(new OrderCreatedEvent(order.getId()));
    }
}

// 3. 이벤트 리스너
@Component
public class OrderEventHandler {

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("주문 생성됨: " + event.getOrderId());
    }
}

동작 방식

  • publishEvent() 가 호출되면, 해당 이벤트 타입을 파라미터로 받는 @EventListener메서드들이 동기적으로, 즉시 실행됨.

  • 기본적으로 같은 스레드에서, 호출한 시점 그대로 실행 (트랜잭션 진행 중이면 그 안에서 실행됨)

  • 여러 리스너가 같은 이벤트를 구독할 수 있음 -> 발행자는 누가 듣는지 몰라도 됨(느슨한 결합)

왜 쓰나

관심사 분리가 핵심, 예를 들어 주문 생성 시:

  • 재고 차감
  • 이메일 발송
  • 통계 업데이트
  • 포인트 적립

이런 걸 전부 OrderService.createOrder() 안에 몰아넣으면 메서드가 비대해지고 책임이 섞인다. 대신 OrderCreatedEvent만 발행하고, 각 관심사는 별도의 리스너로 분리하면 코드가 깔끔해지고 서로 독립적으로 테스트/수정 가능해진다.

@TransactionalEventListener와의 차이

@EventListener@TransactionalEventListener
실행 시점이벤트 발행 즉시트랜잭션 커밋/롤백 후 (지정한 phase)
트랜잭션 없을 때그냥 실행됨기본적으로 실행 안 됨 (옵션으로 강제 가능)
용도일반적인 이벤트 처리DB 반영 확정 후에만 처리해야 하는 경우

주의할 점

  • 기본은 동기 실행이라, 리스너 안에서 예외가 터지면 발행자 쪽까지 예외가 전파됨(트랜잭션이면 롤백 가능)
  • 리스너가 느리면 발행자도 그만큼 느려짐 -> 이게 싫으면 Async를 추가로 붙여야 함
  • @EventListener는 같은 애플리케이션(JVM) 안에서만 동작 (다른 서버로 메시지 보내는 게 아님). 분산 환경에서 이벤트를 쓰려면 Kafka, RabbitMQ 같은 메시지 브로커가 필요함

0개의 댓글