Spring 이벤트 프로그래밍에 유용한 인터페이스인 ApplicationEventPublisher

2 minute read

ApplicationEventPublisher

스프링의 ApplicationEventPublisher는 옵저버 패턴 기반으로 이벤트 프로그래밍을 할 때 필요한 인터페이스를 제공한다.

이벤트 생성

Spring 4.2 이하 버전은 ApplicationEvent 클래스를 상속 받아서 이벤트를 만들 수 있다.

아래는 데이터를 받는 이벤트 생성 예제이다.

MyEvent.java

이벤트 객체는 ApplicationEvent 클래스를 상속 받아 생성하고 빈으로 등록할 필요는 없다.

public class MyEvent extends ApplicationEvent {
	
	private int data;
	private String str;
	
	public MyEvent(Object source) {
		super(source);
	}
	
	public MyEvent(Object source, int data, String str) {
		super(source);
		this.data = data;
		this.str = str;
		
	}
	
	public int getData() {
		return data;
	}
	
	public String getString() {
		return str;
	}
}


이벤트 처리

MyEventHandler.java

  • 이벤트 수신 핸들러를 ApplicationListener 인터페이스를 상속받아 생성
  • 빈으로 등록
@Component
public class MyEventHandler implements ApplicationListener<MyEvent>{

	@Override
	public void onApplicationEvent(MyEvent event) {
		System.out.println("My Event Handler:  "+event.getData()+", "+event.getString());
	}
	
}


AppRunner.java

  • publishEvent로 이벤트를 발생시킨다.

  • ApplicationEventPublisher는 ApplicationContext 안에 속하는 IoC 컨테이너 기능 중 하나이므로 ApplicationContext로 사용 가능

@Component
public class AppRunner implements ApplicationRunner {

	@Autowired
	ApplicationEventPublisher publishEvent;
	//ApplicationContext applicationContext;
	
	
	@Override
	public void run(ApplicationArguments args) throws Exception {
		publishEvent.publishEvent(new MyEvent(this, 100, "User"));
		//applicationContext.publishEvent(new MyEvent(this, 100, "User"));

	}
}


이벤트 생성 및 처리(Spring 4.2 이상)

Spring 4.2 버전 부터 코드 내에 프레임워크 소스가 없는 구조인 POJO 형식으로 프로그래밍이 가능해졌다.

MyEvent.java

  • ApplicationEvent를 상속하지 않아도 된다.
public class MyEvent {
	
	private int data;
	private String str;
	
	private Object source;
	
	public MyEvent(Object source, int data, String str) {
		this.source = source;
		this.data = data;
		this.str = str;
		
	}
	
	public int getData() {
		return data;
	}
	
	public String getString() {
		return str;
	}
	
	public Object getSource() {
		return source;
	}
}


MyEventHandler.java

  • ApplicationListener를 상속하지 않아도 된다.
  • 메소드명을 임의로 수정할 수 있다.
  • @EventListener 어노테이션 사용
@Component
public class MyEventHandler {

	@EventListener
	public void handleMyEvent(MyEvent event) {
		System.out.println("My Event Handler:  "+event.getData()+", "+event.getString());
	}
	
}


다수의 핸들러 처리

  • 여러개의 핸들러가 있을 때 임의로 순차적 실행이 된다.

  • 순서를 정할 땐 @Order 어노테이션을 같이 사용한다.

    AnoterHandler.java

    @Component
    public class AnotherHandler {
      	
    	@EventListener
    	@Order(Ordered.HIGHEST_PRECEDENCE)
    	public void handle(MyEvent myEvent) {
    		System.out.println("Another Event Handler: "+myEvent.getData());
    	}
    }
      
    
  • 비동기적으로 실행할 땐 @Async 어노테이션을 사용한다. (메인 소스에 @EnableAsync 어노테이션을 같이 사용해야 한다.)

  • 비동기 실행 시 순서는 보장 안된다.

    MyHandler.java

    @Component
    public class MyEventHandler {
      
    	@EventListener
    	@Async
    	public void handleMyEvent(MyEvent event) {
    		System.out.println("My Event Handler: "+event.getData()+", "+event.getString());
    	}
      	
    }
    


    AnoterHandler.java

    @Component
    public class AnotherHandler {
      	
    	@EventListener
    	@Async
    	public void handle(MyEvent myEvent) {
    		System.out.println("Another Event Handler: "+myEvent.getData());
    	}
    }
    


    ProjcetApplication.java

    @SpringBootApplication
    @EnableAsync
    public class Demo4Application {
      
    	public static void main(String[] args) {
    		SpringApplication.run(Demo4Application.class, args);
    	}
      
    }
    

스프링 기본 이벤트

  • ContextRefreshedEvent
    ApplicationContext가 초기화 및 리프레시 할 때 발생한다.

    	@EventListener
    	@Async
    	public void handleMyEvent(ContextRefreshedEvent event) {
    		System.out.println("ContextRefreshedEvent");
    	}
      	
    
  • ContextStartedEvent

ApplicationContext가 start되어 라이프사이클 빈들이 시작신호를 받는 시점에 발생

  • ContextStoppedEvent

    ApplicationContext가 stop되어 라이프사이클 빈들이 정지신호를 받는 시점에 발생

  • ContextClosedEvent
    ApplicationContext가 close되고 빈 소멸되는 시점에 발생한다.

    	@EventListener
    	@Async
    	public void handleMyEvent(ContextClosedEvent event) {
    		System.out.println("ContextClosedEvent");
    	}
    
  • RequestHandledEvent
    HTTP 요청을 처리했을 때 발생한다.

Reference

ApplicationEventPublisher 인터페이스

@EventListener Annotation

Categories:

Updated:

Comments