개요
옵저버 패턴의 구현체로서, 이벤트 기반의 프로그래밍을 할 때 유용한 인터페이스.
실습을 위한 주요 구성 요소
퍼블리셔, 이벤트, 이벤트핸들러
이벤트
- ApplicationEvent 상속
public class MyEvent extends ApplicationEvent {private int data; public MyEvent(Object source){ super(source); } public MyEvent(Object source, int data){ super(source); this.data=data; } public int getData(){ return data; }}- 스프링 4.2부터는 "ApplicationEvent" 클래스를 상속 받지 않아도 이벤트로 사용 가능하다.
용어
비침투성(non-invasive, transparent)이란 스프링 프레임 워크의 코드가 직접 작성하는 코드 layer에는 노출되지 않는 것이다.
이벤트 발생시키는 방법
- ApplicationEventPublisher.publishEvent()
@Componentpublic class AppRunner implements ApplicationRunner { @Autowired ApplicationEventPublisher publishEvent; @Override public void run(ApplicationArguments args) throws Exception { publishEvent.publishEvent(new MyEvent(this, 100)); }}
@Component를 추가하여 Bean으로 만든다.
이벤트 처리하는 방법
- ApplicationListner<이벤트> 구현한 클래스 만들어서 빈으로 등록한다.
- 스프링4.2부터는 @EventListener를 사용하면 interface를 상속할 필요는 없다.
//스프링 4.2 이전@Componentpublic class MyEventHandler extends ApplicationListener<MyEvent> { private int data; @Override public void onApplicationEvent(MyEvent myEvent) { System.out.println(event.getData()); }}//스프링 4.2 이후@Componentpublic class MyEventHandler{ @EventListener public void handle(MyEvent event){ System.out.println(event.getData()); }}- 기본적으로는 synchronized : 다른 Handler를 두어 실행하면 별개의 설정이 없을 경우 동일 스레드 실행. 순서는 랜덤.
- 순서를 정하고 싶다면 @Order와 함께 사용한다.
@Componentpublic class MyEventHandler{ @EventListener @Order(Ordered.HIGHEST_PRECEDENCE)// (HIGHEST_PRECEDENCE+1) 보다 앞서 실행 public void handle(MyEvent event){ System.out.println(event.getData()); }}- 비동기적으로 실행하고 싶다면 @Async와 함께 사용한다.
@Componentpublic class MyEventHandler{ @EventListener @Async public void handle(MyEvent event){ System.out.println(event.getData()); }}
이 경우는 비동기 실행이므로 스레드가 분리되며, @Order는 따라서 의미가 없다. @EnableAsync를 App class에 annotation으로 추가하여야 한다.
스프링이 제공하는 기본 이벤트
- ContextRefreshedEvent: ApplicationContext를 초기화한 후 리프레시 했을 때 발생.
- ContextStartedEvent: ApplicationContext를 start()하여 라이브사이클 빈들이 시작 신호를 받은 시점에 발생
- ContextStoppedEvent: ApplicationContext를 stop()하여 라이브사이클 빈들이 시작 신호를 받은 시점에 발생
- ContextClosedEvent: ApplicationContext를 close()하여 싱글톤 빈이 소멸되는 시점에 발생
- 아래 코드처럼 각각 handling할 수 있다.
@Componentpublic class MyEventHandler{ @EventListener @Async public void handle(MyEvent event){ // } @EventListener @Async public void handle(ContextRefreshedEvent event){ // } @EventListener @Async public void handle(ContextClosedEvent event){ // }}