리스너는 특정 이벤트가 발생하기를 '귀 기울여' 기다리다가 실행되는 컴포넌트(메서드나 함수)를 말한다.
꼭 입출력과 관련된것만이 이벤트는 아니며, 이 글에서 설명하려는 Servlet/JSP의 리스너와 같이 웹어플리케이션의 시작이나, 종료, 특정 객체의 생성, 소멸과 같은것도 이벤트라고 할 수 있습니다. 추가적으로 이벤트 소스가 있는데 이벤트 소스는 이벤트가 발생한 대상(이벤트 발생원)을 말합니다. 앞서 설명했던 '마우스 클릭' 이라는 이벤트의 이벤트 소스는 마우스입니다.
-
이벤트 - 발생한 특정 사건(마우스 클릭, 키보드 입력, 클라이언트로부터의 HTTP 요청, 웹어플리케이션 시작, 웹어플리케이션 종료 등)
-
이벤트 소스 - 이벤트가 발생한 대상(근원지)으로 마우스, 키보드, 웹어플리케이션(ServletContext) 등
-
리스너, 핸들러 - 이벤트가 발생되기를 기다렸다가 발생시 실행되는 메서드나 함수. 또는 메서드를 가진 객체
즉 정리하자면 리스너는 수많은 이벤트 소스들로부터 이벤트가 발생하기를 기다리는(귀 기울여 청취하는) 컴포넌트(함수나 객체)입니다. Java에서 리스너는 객체가 되며, 특정 이벤트가 발생했을때 실행되는(이벤트를 처리할) 메서드를 가지고 있습니다.
Spring @EventListener
도메인 사이에 강한 의존성으로 인해 시스템이 복잡해지는 경우가 발생하는 데 의존성을 줄이기 위한 방법으로 @EventListner를 사용한다.
이벤트 리스너는 ApplicationListener를 구현할 필요가 없고 즉 정리하자면 리스너는 수많은 이벤트 소스들로부터 이벤트가 발생하기를 기다리는(귀 기울여 청취하는) 컴포넌트(함수나 객체)입니다. Java에서 리스너는 객체가 되며, 특정 이벤트가 발생했을때 실행되는(이벤트를 처리할) 메서드를 가지고 있습니다.
@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를 활용해보도록 하겠습니다.
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마다 저러한 클래스들을 만들기엔 상당히 귀찮고 힘들죠.
@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);
실행.
'Spring > 개념' 카테고리의 다른 글
스프링, 스프링 부트 비교 (0) | 2022.08.23 |
---|---|
스프링 빈 생애주기(Life Cycle) (0) | 2022.07.15 |
URI, URL 비교 (0) | 2022.05.30 |
equals, Null Pointer Exception 없이 사용하기 (0) | 2022.05.26 |
rs.next() 의 의미 (0) | 2022.03.02 |