티스토리 뷰
모든 소스는 Github에 있습니다.
안녕하세요.
오늘은 @EventListner 에 대해 공유해보도록 하겠습니다.
도메인 사이에 강한 의존성으로 인해 시스템이 복잡해지는 경우가 발생하는데
의존성을 줄이기 위한 방법으로 @EventListner를 소개하겠습니다.
Case 1.
우선 예시로 좋은 주문예시를 들도록 하겠습니다.
주문을 하게되면 발생하는 이벤트들이 있을겁니다.
예를 들면, 주문완료 카톡발송, 이메일 발송 등이 있을 수 있습니다.
아래의 코드를 보겠습니다.
@Service
public class OrderService {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@Transactional
public void save(OrderRequestDto body) {
System.out.println("ORDER PROCESSING...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ORDER SUCCESS");
sendKakao();
}
public void sendKakao() {
System.out.println("SEND KAKAO MESSAGE");
}
public void sendEmail() {
System.out.println("SEND EMAIL");
}
}
위 save()
를 주문을 처리하는 기능이라고 생각해보겠습니다.
주문을 처리한 후 메시지를 보내는 메소드를 호출하고 있습니다.
이렇게 할 경우 주문을 처리하는 로직과 메시지를 발송(sendKakao()
)하는 로직이 섞이게 됩니다.
이와 같은 의존성을 줄이기 위해 ApplicationEvent
, @EventListner
를 활용해보도록 하겠습니다.
개선 1. ApplicationEvent
-
Order.java
public class Order { private Long orderId; private String name; private String price; private String method; // *** GETTER, SETTER,CONSTRUCTOR 생략 *** }
주문 POJO객체이다. 간단한
getter
,setter
,toString()
를 만들어줍니다. (Lombok을 사용하면 짧게 가능합니다) -
OrderEvent.java
import org.springframework.context.ApplicationEvent; public class OrderEvent extends ApplicationEvent { private Order data; public OrderEvent(Object source) { super(source); } public OrderEvent(Object source, Order data) { super(source); this.data = data; } public Order getData() { return data; } }
ApplicationEvent
를 상속하는 클래스를 만들어줍니다. -
MessageService.java
메시지를 발송하는 Service입니다.
@Service public class MessageService { public void sendKakao() { System.out.println("SEND KAKAO MESSAGE"); } public void sendEmail() { System.out.println("SEND EMAIL"); } }
-
OrderHandler.java
@Component public class OrderHandler implements ApplicationListener<OrderEvent> { @Autowired MessageService messageService; @Override public void onApplicationEvent(OrderEvent order) { System.out.println("REQUEST SENDING KAKAO"); messageService.sendKakao(); } }
@Component
Bean으로 등록해줘야합니다.ApplicationListner
를 구현하는 클래스를 만들어줍니다.ApplicationListner<T>
T 에는 이벤트를 발행할 클래스로 등록해줍니다. -
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"); try { Thread.sleep(1000); // 처리되는 느낌... } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("ORDER SUCCESS"); applicationEventPublisher.publishEvent(new OrderEvent(this, order)); } }
이제 주문을 처리하는 (척) 하는 Service를 만들어줍니다.
ApplicationEventPublisher
를 주입받습니다.그리고,
Order
객체를 만들어주고publishEvent()
에OrderEvent
를 생성해서 이벤트를 발생시킨다.그리고 테스트를 도와줄
ApplicationRunner
를 구현한OrderRunner
도 만들어줍니다. -
OrderRunner.java
@Component public class OrderRunner implements ApplicationRunner { @Autowired OrderService orderService; @Override public void run(ApplicationArguments args) throws Exception { // 주문 요청하는척... System.out.println("REQUEST ORDER"); orderService.save(); System.out.println("FINISHED"); } }
실행.
정상적으로 Event를 발행, 실행된 것을 확인할 수 있습니다.
위에 코드는 Event를 발행하기 위한 많은 코드가 존재합니다.
Event마다 저러한 클래스들을 만들기엔 상당히 귀찮고 힘들죠.
개선 2. @EventListner
그래서 Spring 4.2 부터 사용 가능한 @EventListner 어노테이션을 사용하여 이벤트를 처리해보겠습니다.
@EventListner를 사용하면 ApplicationEvent, ApplicationListner 상속, 구현 할 필요가 없습니다.
위에서 만든 코드들을 조금 수정해보겠습니다.
-
OrderHandler.java
@Component public class OrderHandler { @Autowired private MessageService messageService; @EventListener public void sendKakaoAfterOrder(Order order) { System.out.println("REQUEST SENDING KAKAO"); messageService.sendKakao(); } }
받는 파라미터도 POJO객체
Order
로 변경하였습니다.훨씬 간결해진것을 볼 수 있습니다.
파라미터를
Order
로 변경했으니 이벤트를 발행할 때도 변경해줘야합니다. -
OrderService.java
applicationEventPublisher.publishEvent(new OrderEvent(this, order));
를 아래와 같이 변경해줍니다.applicationEventPublisher.publishEvent(order);
이제 프로젝트를 실행시키면,
똑같은 결과를 볼 수 있습니다.
만약 이메일 전송을 추가하고 싶다면,
@EventListener
public void sendEmailAfterOrder(Order order) {
System.out.println("REQUEST SENDING EMAIL");
messageService.sendEmail();
}
한가지 더 추가 해주면
이메일까지 전송할 수 있게됩니다~
개선사항..
아직까지 이벤트는 순차적으로 실행됩니다.
만약 메일 전송로직이 실패하면 주문처리 로직까지 실패하게 될 수 있습니다.
이러한 문제를 해결할 수 있는 방법은 다음 포스팅에서 다루도록 하겠습니다.
도움이 되었길 바라며..
감사합니다.
References
https://ivvve.github.io/2019/06/02/java/Spring/event-listener-2/
'Dev > Spring' 카테고리의 다른 글
[security] 1. 기본 설정 (0) | 2021.05.11 |
---|---|
Spring @EventListner 사용해보기 - 2 (0) | 2020.11.22 |
Spring boot 에러처리하기! (feat. @ExceptionHandler & @ControllerAdvice) (0) | 2020.11.12 |
Spring Web Static Resources (0) | 2020.11.11 |
Spring boot 프로젝트 만들기 (0) | 2020.10.21 |
- Total
- Today
- Yesterday
- booleanExpression
- ResourceHttpReqeustHandler
- 웹서비스
- API
- 스프링
- ControllerAdvice
- springsecurity
- FastAPI
- Security
- JPA
- boot
- 스프링부트
- 자바
- spring web
- QueryDSL
- springboot
- howtoinstallnginx
- java11
- Spring
- 스프링부트 시작하기
- @formula
- 개발
- paawordencoder
- 스프링시큐리티
- like절
- Python
- 유사결과
- ubuntu
- Java
- mapstruct
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |