@EventListener
- @EventListener 애너테이션의 역할, 동작 방식
- 메서드 기반 이벤트 리스너를 구현, 실행 흐름 파악
- 조건부 이벤트 리스너 구현(condition 속성)
- SpEL(Spring Expression Language)를 활용해 이벤트 필터링 구현
- 이벤트 기반 구조에서 유연성, 확장성을 높이는 방법
@EventListener
이벤트 클래스, 퍼블리셔, 리스너 이후에 애너테이션을 활용하여 메서드 단위로 이벤트를 처리하는 법
@EventListener는 기존의 ApplicationListener를 대체하여 더 간결하고 가독성 높은 방식으로 이벤트 리스너를 작성하게 해줌
1. 메서드 기반 이벤트 리스너
implements를 활용한 기존의 이벤트 리스너 구현
public class UserRegisteredEventListener
implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("회원가입 이벤트 수신" + event.getEmail());
// 이후 비즈니스 로직 구현
}
}
Spring 4.2 이후 @EventListener를 메서드에 붙이는 방식
@Component
public class UserEventHandler {
@EventListener // UserRegisteredEvent 타입의 이벤트가 발생할 때 자동으로 실행된다고 함
public handlerUserRegistered(UserRegisteredEvent event) {
// 대충 비즈니스 로직
System.out.println("회원가입 완료" + event.getEmail());
}
}
방식의 차이에 대한 비교
| 비교 | ApplicationListener implements 방식 | @EventListener 애너테이션 방식 |
| 작성 구조 | 클래스 단위로 구현 | 메서드 단위로 구현 |
| 가독성 | 낮음(상속 필요) | 높음(애너테이션만으로 구현) |
| 유지보수 | 이벤트 타입 추가시 클래스를 추가해줘야함 | 한 클래스에서 여러 이벤트 처리 가능 |
2. 하나의 클래스에서 여러 이벤트 처리하기
@EventListener는 메서드에 붙이는 애너테이션이기 때문에 하나의 클래스에서 여러 메서드에 @EventListener를 붙여주면 여러 이벤트를 처리할 수 있다.
다만 트랜잭션에서 봤던 Self-Invocation에 대해서 고려해보면 좋을것이다.
@Component
public class UserEventHandler {
@EventListener
public void handleUserRegistered(UserRegisteredEvent event) {
System.out.println("회원가입 완료 : " + event.getEmail());
}
@EventListener
public void handleUserDeleted(UserDeletedEvent event) {
System.out.println("회원탈퇴 완료 " + event.getUserId());
}
}
이런식으로 하나의 리스너 클래스에서 CRUD를 구현할 수 있다.
3. 디렉토리 구조 예시
src/main/java/com/example/demo/
event/
UserRegisteredEvent.java
UserDeletedEvent.java
UserEventHandler.java < - 여러 이벤트를 처리하는 클래스, 분리도 가능하다
service/
UserService.java < - 이벤트 발행자, 퍼블리셔
조건부 이벤트 처리(Condition 속성)
@EventListener 애너테이션은 condition 속성을 활용해서 특정 조건일때만 이벤트를 처리할 수 있다고 함
1. 기본 구조
public class ConditionalUserEventHandler {
@EventListener(condition = "#event.premium == true") // 여기
public void handlePremiumUser(UserRegisteredEvent event) {
System.out.println("프리미엄 회원 처리 " + event.getEmail());
}
}
UserRegisteredEvent의 premium 필드가 true일때만 실행되는 이벤트 리스너이다.
이벤트를 발행할 때(서비스에서 퍼블리싱 할 때) 프리미엄의 여부를 함께 전달하면 이벤트로 받을 수 있을 것이다.
// 서비스
publisher.publishEvent(new UserRegisteredEvent("b1uffer@example.com", true)); // 프리미엄 true
이 때 premium == false라면 이벤트가 무시된다.
SpEL(spring Expression Language) 활용
SpEL은 런타임에 객체의 값을 표현식으로 평가할 수 있는 강력한 기능을 제공해준다고 한다.
@EventListener(condition = "") 내부에 SpEL을 활용하면 이벤트 속성을 기반으로 정교한 조건식을 만들 수 있다.
1. SpEL 문법 기본
| 문법 | 설명 | 예시 |
| #event | 현재 이벤트 객체를 참조함 | #event.email |
| 논리 연산 | 조건 조합 | #event.age > 20 and #event.active |
| 문자열 연산 | 문자열을 비교함 | #event.email matches '.*@vip.com' |
2. 예시
@Component
public class VipUserEventHandler {
// 이메일이 특정 도메인(@vip.com)일 때만 실행한다. 정규식을 활용한거임
@EventListener(condition = "#event.email matches '.*@vip.com'")
public void handleVipUser(UserRegisteredEvent event) {
System.out.println("VIP 회원입니다. " + event.getEmail());
}
}
이메일 주소가 @vip.com으로 끝나는 사용자에 대해서만 리스너가 반응한다.
이벤트 리스너 호출 흐름
퍼블리셔 - 스프링 컨테이너 - 이벤트 - 리스너 형태가 될 것인데, 여기에 @EventListener가 껴있을 뿐이다.
팁
| 요소 | 역할 | 예시 |
| @EventListener | 이벤트를 메서드 단위로 처리함 | handleUserRegistered() |
| condition 속성 | 이벤트 처리 조건 지정 | condition = #event.premium == true |
| SpEL | 동적 조건 표현식 평가 | #event.email matches '.*@vip.com' |
| ApplicationEventPublisher | 이벤트 발행 및 전달 | publishEvent() |
'Spring Boot > 비동기 처리' 카테고리의 다른 글
| Spring Event : 분산 환경으로의 확장 가능성 (0) | 2025.10.29 |
|---|---|
| Spring Event : 이벤트 기반 비동기 처리 활용사례 (0) | 2025.10.29 |
| Spring Event : 비동기 이벤트 처리 구현 (0) | 2025.10.25 |
| Spring Event : 기본 이벤트 처리 방식 (0) | 2025.10.24 |
| Spring Event : Spring Event? (0) | 2025.10.24 |