article thumbnail image
Published 2022. 8. 29. 14:09

리스너는 특정 이벤트가 발생하기를 '귀 기울여' 기다리다가 실행되는 컴포넌트(메서드나 함수)를 말한다.

 

리스너는 이벤트가 발생함과 동시에 특정 행동을(메서드나 함수를 실행)하는데, 이것을 이벤트 핸들링이라고 합니다. 따라서 리스너를 이벤트 핸들러라고 부르기도 합니다.

 

여기서 이벤트라는 말이 등장하는데, 이벤트발생한 특정 사건이나 일을 말하는데, 예를 들어보자면 마우스 클릭, 키보드 키 입력, 버튼 클릭, 텍스트 입력 등이 있습니다.
 

꼭 입출력과 관련된것만이 이벤트는 아니며, 이 글에서 설명하려는 Servlet/JSP의 리스너와 같이 웹어플리케이션의 시작이나, 종료, 특정 객체의 생성, 소멸과 같은것도 이벤트라고 할 수 있습니다. 추가적으로 이벤트 소스가 있는데 이벤트 소스는 이벤트가 발생한 대상(이벤트 발생원)을 말합니다. 앞서 설명했던 '마우스 클릭' 이라는 이벤트의 이벤트 소스는 마우스입니다.

 

그런 개념에서는 클라이언트로부터의 요청(이벤트)이 발생했을때 실행되는 Servlet도 일종의 리스너라고 할 수 있습니다.
 
  • 이벤트 - 발생한 특정 사건(마우스 클릭, 키보드 입력, 클라이언트로부터의 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
복사했습니다!