티스토리 뷰
안녕하세요.
저번 포스팅에 이어 Spring @EventListner 2편입니다.
모든 소스코드는 Github에서 확인하실 수 있습니다.
비동기로 이벤트를 처리해보자.
이전에 포스팅에서는 이벤트가 순서대로 처리가 되었습니다.
이번 포스팅에서는 각각의 이벤트를 비동기로 처리하는
방법에 대해 알아보겠습니다.
현재 코드를 조금 수정을 하였습니다.
각각의 기능의 3초, 2초간 sleep을 하여 실행하게 하였고
결과를 확인해보면 각각 2초, 3초가 걸리고 총 약 5초가 실행시간으로
나오게 됩니다.
이유는 Log에서도 볼 수 있듯이 같은 Thread에서 처리를 하고 있기 때문입니다.
이제 비동기로 실행하는 방법을 보겠습니다.
우선 각각의 @EventListner
위에 @Asnyc
어노테이션을 붙여주었습니다.
그리고 Main 실행 클래스에 @EnableAsync
어노테이션도 추가해주었습니다.
해당 어노테이션이 있어야 비동기로 작동하니 꼭 추가해주시기 바랍니다.
위와 같이 수정 후 실행해보면 기존에는 약 5초가 나오던 Runner Task Time 이 바로 종료가 되었고,
아래에 Send를 하는 기능은 기존과 동일하게 2초, 3초가 나왔습니다.
Thread 이름을 보게 되면 각각 다른 Thread에서 동작했다는 것을 알 수 있습니다.
총 3개의 Thread에서 동작하였습니다.
- Thread 1 - Spring Runner
- Thread 2 - sendKakao()
- Thread 3 - sendEmail()
이렇게 위와 같이 한다면 각각의 이벤트를 비동기로 좀 더 빠르게 처리를 할 수 있게 됩니다.
Event Exception 분리
추가로 한 가지만 더 보도록 하겠습니다.
만약 Push를 전송 중 에러가 발생한다면?
주문을 처리하는 로직에서도 문제가 전파될 수 있습니다.
이벤트의 Exception을 독립적으로 처리할 수 있는 방법을 알아보겠습니다.
OrderService.java
@Service public class OrderService { @Autowired ApplicationEventPublisher applicationEventPublisher; public void save() { System.out.println("ORDER PROCESSING..."); Order order = new Order(); order.setOrderId(1L); order.setName("ALXNDR"); order.setPrice("10000"); order.setMethod("CREDIT"); applicationEventPublisher.publishEvent(order); System.out.println("ORDER SUCCESS"); } }
이벤트를 발행한 후 Order Success라는 문장을 출력하게 했습니다.
MessageService.java
public void sendPushMessage() { throw new RuntimeException("PUSH 메시지 전송 중 에러가 발생하였습니다."); }
위와 같이
MesaageService
에 푸시 기능을 하나 만들어줍니다.해당 메서드는 무조건
RuntimeException
을 발생시킵니다.OrderHandler.java
@EventListener public void sendPushEvnet(Order order) { messageService.sendPushMessage(); }
위에서 만든 푸시 기능을 호출하는 이벤트를 만들어주고 실행해보겠습니다.
Push 메시지 기능을 실행 중 Exception
이 발생하였고, OrderService
에서 출력하려고 했던 OrderService
에서 출력하려고 했던 Order Success가 찍히지 않습니다.
그 이후에 로직에도 영향을 미치고 있죠.
Exception 분리
@TransactionalEventListener
를 이용하면 Exception
이 발생하더라도 주문기능에 끼치는 영향을 제거할 수 있습니다.
build.gradle
dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly('com.h2database:h2') testImplementation 'org.springframework.boot:spring-boot-starter-test' }
@Transactional
이 필요하기 때문에 data-jpa
와 H2
의존성을 추가해줍니다.
우선 같은 Transaction
에서 작동하기 때문에 OrderService
에 @Transaction
을 추가해줍니다.
@Service
public class OrderService {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@Transaction
public void save() {
System.out.println("ORDER PROCESSING...");
Order order = new Order();
order.setOrderId(1L);
order.setName("ALXNDR");
order.setPrice("10000");
order.setMethod("CREDIT");
applicationEventPublisher.publishEvent(order);
System.out.println("ORDER SUCCESS");
}
}
그리고 Push 메서드에 @EventListner
를 @TransactionalEventListner
로 변경해줍니다.
@TransactionalEventListener
public void sendPushEvent(Order order) {
System.out.println("PUSH MESSAGE SENDING....");
messageService.sendPushMessage();
}
위와 같이 수정한 후 실행해보면 로그가 정상적으로 출력되고 주문 기능도 정상적으로 종료되었음을 확인할 수 있습니다.
틀린 부분이나 개선 사항 있다면
알려주시면 감사하겠습니다.
감사합니다.
References
https://ivvve.github.io/2019/06/02/java/Spring/event-listener-2/
'Dev > Spring' 카테고리의 다른 글
[security] 2. Inmemory User (0) | 2021.05.11 |
---|---|
[security] 1. 기본 설정 (0) | 2021.05.11 |
Spring @EventListner 사용해보기 (0) | 2020.11.18 |
Spring boot 에러처리하기! (feat. @ExceptionHandler & @ControllerAdvice) (0) | 2020.11.12 |
Spring Web Static Resources (0) | 2020.11.11 |
- Total
- Today
- Yesterday
- JPA
- 웹서비스
- @formula
- howtoinstallnginx
- booleanExpression
- 스프링부트 시작하기
- 스프링시큐리티
- API
- QueryDSL
- 개발
- paawordencoder
- ControllerAdvice
- 스프링
- Spring
- 자바
- java11
- spring web
- springsecurity
- mapstruct
- ResourceHttpReqeustHandler
- springboot
- Java
- 스프링부트
- Security
- FastAPI
- boot
- ubuntu
- 유사결과
- like절
- Python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |