Event?
Spring에서는 특정 동작이나 프로세스가 수행될 때, 특수한 행동을 일으키는 이벤트 라는 개념이 존재합니다.
예를 들면, JPA의 경우 엔티티의 감지를 위해 다음과 같은 리스너 어노테이션을 사용하고 있는 것을 볼 수 있는데요,
@Entity
@EntityListeners(UserEntityListener.class)
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
// Getters and setters...
}
이처럼 Spring 이벤트는 특정 동작이 수행될 때, 비즈니스 로직과 별개의 동작을 수행하는 이벤트를 처리할 수 있는 기능을 제공 해 주고 있는데, 오늘은 이에 대해서 알아보려고 합니다.
Spring Event란?
Spring Event는 애플리케이션 내에서 상태 변화나 특정 동작을 다른 컴포넌트에 전달하기 위해 사용되는 경량 이벤트 기반 메커니즘으로,
이벤트 발행자는 특정 이벤트를 발행하고, 이벤트 리스너는 이를 구독하여 비동기적 또는 동기적으로 처리할 수 있는 특징을 가지고 있습니다.
Spring Event의 두 가지 기능
Event Publisher
- 특정 작업이나 상태 변화가 발생했을 때 이벤트를 발행하는 역할을 합니다.
- ApplicationEventPublisher를 통해 이벤트를 발행할 수 있습니다
Event Listener
- 발행된 이벤트를 처리하는 역할을 합니다.
- @EventListener 어노테이션을 사용하여 리스너 메서드를 정의할 수 있습니다.
Spring Event 사용 방법
// publisher
@Service
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
public OrderService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void createOrder(String orderId) {
// Order 생성 로직
eventPublisher.publishEvent(new OrderCreatedEvent(orderId));
}
}
// Listener
@Component
public class OrderEventListener {
@EventListener
public void handleOrderCreatedEvent(OrderCreatedEvent event) {
System.out.println("Order created: " + event.getOrderId());
}
}
Spring Event의 동작 원리
ApplicationEventPublisher를 통해 발행 된 이벤트는 다음과 같이 Spring Context의 Event를 관리하는 변수에서 저장되고 있습니다.
이벤트가 발행될 때 @EventListener를 사용하는 리스너들은 다음 SimpleApplicationEventMulticaster에서 등록 된 리스너들 중에 발행 된 이벤트와 일치하는 리스너를 호출하게 되는 구조입니다.
Spring Event는 비동기인가?
저는 Spring Event를 사용하면서 "어라? 이벤트는 비동기적으로 동작하지 않나..? 🤔" 라고 생각했었는데요,
위 내부 구성을 보니, 이벤트가 발행될 때 따로 비동기적으로 수행되는 것이 아니라 이벤트 그 자체로는 동기적으로 수행되는 것을 볼 수 있습니다.
내부 코드를 보면서 제 착각을 바로잡을 수 있었는데, 이벤트라고 하는 기능은 사실 그 자체로 비동기성을 갖춘 것이 아니라 "특정 상황이 발생할 경우 이를 수행한다"라는 비동기에 대한 함축적 의미를 담고 있는 동기적 행위였네요! 😅
그러면, 비동기로 이벤트를 사용하려면 어떻게 해야할까?
다음과 같이 EventListener를 사용하는 위치에 @Async 어노테이션을 추가하면 간단하게 비동기로 처리할 수 있습니다.
@Component
public class OrderEventListener {
@Async
@EventListener
public void handleOrderCreatedEvent(OrderCreatedEvent event) {
System.out.println("Order created: " + event.getOrderId());
}
}
JPA로 알아보는 Spring Event의 대표적인 사례
// 도메인 클래스
public class UserCreatedEvent {
private final Long userId;
public UserCreatedEvent(Long userId) {
this.userId = userId;
}
public Long getUserId() {
return userId;
}
}
// 엔티티 리스너
@Entity
@EntityListeners(UserEntityListener.class)
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
// Getters and setters...
}
// 리스너 구현
public class UserEntityListener {
@PostPersist
public void onPostPersist(User user) {
ApplicationContextProvider.getApplicationContext()
.publishEvent(new UserCreatedEvent(user.getId()));
}
}
// 이벤트 리스너
@Component
public class UserEventListener {
@EventListener
public void handleUserCreated(UserCreatedEvent event) {
System.out.println("User created with ID: " + event.getUserId());
// 추가 작업 (예: 이메일 발송)
}
}
결론
오늘은 Spring Event에 대해서 알게 되었던 부분을 나름의 정리를 진행했는데요, 단순한 사용 방법이 아닌 이벤트가 어떻게 동작하는지를 같이 생각 해 보는 좋은 시간이었던 것 같습니다.
'Spring Framework > spring' 카테고리의 다른 글
[SpringBoot] Spring Transaction에 대하여 (0) | 2025.01.06 |
---|---|
[SpringBoot] Spring FIiter (0) | 2024.12.29 |
[SpringBoot] @ComponentScan 동작 원리 (0) | 2024.12.09 |
[SpringBoot] SpringBoot는 어떻게 실행될까? (0) | 2024.12.08 |
MSA 환경에서 Kotlin + Spring Rest Docs + Swagger UI 적용 (0) | 2023.09.14 |