SPRING

[SPRING] @EventListener

도원좀비 2025. 5. 14. 20:00

1️⃣ EventListener란?

@EventListener는 특정 이벤트가 발생했을 때 해당 이벤트를 처리할 메서드를 선언하는 애너테이션

 

Spring 내부에서는 Observer 패턴을 기반으로 동작하며, ApplicationEventPublisher를 통해 이벤트를 발행하고, 등록된 리스너에서 해당 이벤트를 처리


2️⃣ 구조

  1. 이벤트 정의 – 단순 POJO 객체로 정의 가능
  2. 이벤트 발행 – ApplicationEventPublisher로 이벤트 전파
  3. 이벤트 리스너 등록 – @EventListener로 이벤트 처리 메서드 선언

3️⃣ 사용 예시

1. 이벤트 클래스

public class UserRegisteredEvent {
    private final Long userId;

    public UserRegisteredEvent(Long userId) {
        this.userId = userId;
    }

    public Long getUserId() {
        return userId;
    }
}

 

2. 이벤트 발행

@Service
@RequiredArgsConstructor
public class UserService {
    private final ApplicationEventPublisher publisher;

    public void registerUser(User user) {
        // 유저 저장 로직
        // ...
        publisher.publishEvent(new UserRegisteredEvent(user.getId()));
    }
}

 

3. 이벤트 리스너

@Component
public class UserRegisteredListener {

    @EventListener
    public void handleUserRegistered(UserRegisteredEvent event) {
        System.out.println("환영 이메일 발송! 유저 ID: " + event.getUserId());
        // 이메일 전송 로직 등
    }
}

4️⃣ 비동기 처리: @Async와 함께 사용

이벤트 리스너를 비동기적으로 처리하고 싶다면 @Async를 붙이면 됨

@Async
@EventListener
public void handle(UserRegisteredEvent event) {
    // 별도 스레드에서 실행됨
}
이때 @EnableAsync 설정이 필요합니다.

5️⃣ 자주 쓰는 사례

사용 사례 설명
회원가입 후 이메일 발송 메인 트랜잭션과 분리된 후처리
주문 완료 후 알림 전송 관리자/사용자에게 알림
비즈니스 로그 기록 주요 이벤트 트래킹
외부 API 호출 트랜잭션 커밋 이후 호출 시 유용

6️⃣ 한계와 확장: @TransactionalEventListener

기본 @EventListener는 트랜잭션과는 별개로 즉시 실행
트랜잭션이 실패해도 이벤트는 이미 발행됐을 수 있기 때문에 데이터 정합성이 깨질 위험이 있음

이런 경우엔 @TransactionalEventListener를 사용해서 트랜잭션이 성공적으로 커밋된 이후에 이벤트를 처리 가능

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleEvent(Event event) {
    // 트랜잭션 커밋 후 실행
}

7️⃣ 추가

Spring의 @EventListener는 관심사 분리와 코드 유연성을 극대화할 수 있는 훌륭한 도구
특히 다양한 후처리 작업, 알림, 로깅 등에서 유용하게 쓰이며, 간단한 구조로 비동기 처리까지 지원

 

단, 트랜잭션과의 관계가 중요한 경우에는 @TransactionalEventListener를 함께 고려하여 안정적이고 예측 가능한 이벤트 흐름을 설계하는 것이 중요!!