Spring에서 이벤트를 처리하는 방법

probsno·2021년 4월 12일
0

SpringCore

목록 보기
5/9
post-custom-banner

1. 이벤트를 처리하는 방법

  • 이벤트를 발생시키고 처리하기 위해서는 ApplicationEventPublisher라는 인터페이스가 있는데, 이벤트 처리를 하기 위한 인터페이스를 제공하고 옵저버 패턴의 구현체 임.
  • ApplicationContextApplicationEventPublisher를 상속 받기 때문에
    • applicationContext.publishEvent();
    • applicaitonPublishEvent.publishEvent();
    모두 이벤트를 발생시키는 메서드 publishEvent()를 사용 가능함.

1.1 이벤트 객체 만들기

스프링 4.2이전 버전에는 ApplicationEvent 클래스를 상속받아서 이벤트 객체를 만들어야 했음
이벤트 객체 안에 이벤트 발생시에 전달한 데이터같은걸 끼워 넣어서 보낼 수 있슴..

//스프링 4.2 이전에는 ApplicationEvent 클래스를 상속 받아야 했음
public class MyEvent extends ApplicationEvent {

    private int data;
    
    public int getData() {
        return data;
    }

    public MyEvent(Object source) {
        super(source);
    }

    public MyEvent(Object source, int data) {
        super(source);
        this.data = data;
    }
}

하지만 현재는,,,

//스프링 4.2이후ApplicationEvent 클래스를 상속 받지 않아도 됨
public class MyEvent {

    private int data;
    private Object source;
    
    public int getData() {
        return data;
    }
    
    public int getSource() {
        return source;
    }

    public MyEvent(Object source, int data) {
        this.source = source;
        this.data = data;
    }
}

1.2 이벤트 핸들러 만들기

반드시 이벤트 핸들러는 빈으로 등록이 되어야 한다.
그리고, 이벤트 핸들러 역시 스프링 4.2이전에는 ApplicationListener <E> 클래스를 상속받야 했다.
onApplicationEvent 메서드이벤트 객체를 파라미터로 받고 오버라이드 해서 이벤트 발생시 할 동작을 메서드로 정의함!

//event handler는 빈으로 등록해 주어야 한다
//스프링 4.2 이전에는 ApplicationListener<E> 인터페이스를 상속하야함
@Component
public class MyEventHandler implements ApplicationListener<MyEvent> {

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("이벤트 받았음"+myEvent.getData());
    }
}

하지만 지금은,,,
이벤트 발생시 처리하고 싶은 동작메서드에 정의하고 해당 메서드에 @EventHandler 어노테이션만 붙여주면 끝~ (빈으로는 등록해야함)

@Component
public class MyEventHandler {

    @EventListener
    @Async //비동기적으로 실행하고싶다면 @Async 어노테이션을 붙여주면 됨 단, applicaitonRunner에 @EnableAsync도 붙여줘야 멀티스레드 환경에서 돌아감
    @Order(Ordered.HIGHEST_PRECEDENCE) //하나의 이벤트를 처리하는 핸들러가 두개이상일경우 이렇게 순서를 정할 수 있다 (낮을수록 우선순위 숫자로도 줄수 있음)
    public void eventHandleMethod(MyEvent myEvent) {
        System.out.println("이벤트 받았음"+myEvent.getData());
    }
}
  • 이벤트 객체가 하나이고, 한번만 발생시키더라도 이벤트를 처리하는 핸들러(이벤트 리스너)는 2개 이상일 수가 있다. 이런 경우에는 싱글스레드에서 순차적으로 이벤트 핸들러가 실행된다
  • 이벤트 핸들러는 싱글스레드로 실행 되기 때문에 순차적이지만, 순서를 보장하지는 않는다
  • 순서를 보장받기 위해서는 @Order 어노테이션을 붙여서 실행할 순서를 지정해 주면된다
    • @Order(Ordered.HIGHEST_PRECEDENCE)
    • @Order(Ordered.LOWEST_PRECEDENCE)
    • @Order(1) //숫자가 낮을 수록 우선순위임
  • 멀티스레드로 동작하게 하고 싶다면, 메서드에 @Async 어노테이션을 붙여주고 ApplicationRunner@EnableAsync를 붙여주면 멀티스레드로 작동함
@SpringBootApplication
@PropertySource("classpath:/app.properties")
@EnableAsync
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

    }

}

1.3 이벤트 발생 시키기

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    ApplicationEventPublisher applicationEventPublisher;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        applicationEventPublisher.publishEvent(new MyEvent(this, 100));
    }
}
  • applicationEventPublisher 빈의 publishEvent()로 이벤트를 발생 시킬 수 있따~
  • ApplicationContextapplicationEventPublisher 상속받기 때문에
    • application.publishEvent(new MyEvent(this, 100)); 도 가능!

2. 스프링에서 제공하는 기본 이벤트

스프링에서는 ApplicationContext에 관련되어 제공하는 기본 이벤트 들이 있는데....

  • ContextRefreshedEvent: ApplicationContext를 초기화 했더나 리프래시 했을 때 발생
  • ContextStartedEvent: ApplicationContext를 start()하여 라이프사이클 빈들이 시작
    신호를 받은 시점에 발생.
  • ContextStoppedEvent: ApplicationContext를 stop()하여 라이프사이클 빈들이 정지
    신호를 받은 시점에 발생.
  • ContextClosedEvent: ApplicationContext를 close()하여 싱글톤 빈 소멸되는 시점에
    발생.
  • RequestHandledEvent: HTTP 요청을 처리했을 때 발생.

예제를 살펴보자면,,,


    //스프링이 제공하는 기본 이벤트1 - ContextRefreshedEvent
    @EventListener
    public void eventHandleMethod(ContextRefreshedEvent event) {
        //어플리케이션 컨택스트가 초기화되거나 리프레쉬 될때 발생하는 이벤트
        System.out.println(event.getApplicationContext().toString());
    }

    //스프링이 제공하는 기본 이벤트2 - ContextClosedEvent
    @EventListener
    public void eventHandleMethod(ContextClosedEvent event) {
        //어플리케이션 컨택스트가 closed되어 소멸될때 발생하는 이벤트
        System.out.println(event.getApplicationContext().toString());
    }

    //스프링이 제공하는 기본 이벤트3 - ContextStartedEvent
    @EventListener
    public void eventHandleMethod(ContextStartedEvent event) {
        //어플리케이션 컨택스트를 start()해서 라이프사이클 빈들이 시작 신호를 받으면 발생하는 이벤트
        System.out.println(event.getApplicationContext().toString());
    }

    //스프링이 제공하는 기본 이벤트4 - ContextStoppedEvent
    @EventListener
    public void eventHandleMethod(ContextStartedEvent event) {
        //어플리케이션 컨택스트를 stop()하여 라이프사이클 빈이 정지하면 발생하는 이벤트
        System.out.println(event.getApplicationContext().toString());
    }
    
    //스프링이 제공하는 기본 이벤트5 - RequestHandledEvent
    @EventListener
    public void eventHandleMethod(RequestHandledEvent event) {
        //HTTP 요청을 처리했을 때 발생하는 이벤트
        System.out.println("처리완료");
    }
profile
3개국어 쌉가능한 주니어 개발자
post-custom-banner

0개의 댓글