ApplicationContext 가 상속하는 또하나의 인터페이스, ApplicationEventPublisher에 알아본다.
옵저버 패턴 기반의 구현체로서, 이벤트 기반 프로그래밍 시 유용하게 사용된다고 한다.
ApplicationEventListener 는 ApplicationContext 가 상속하고 있는 인터페이스 임으로 주입 받을 수 있다.
package me.soomin.demospring51;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class AppRunner2 implements ApplicationRunner {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
}
이벤트 객체는 빈으로 등록하지 않아도 되며, 원하는 데이터를 필드로 지정하고, 생성자의 값으로 주어 데이터를 전달해 줄 수도 있다.
package me.soomin.demospring51;
public class MyEvent2 {
private int data;
private Object object;
public MyEvent2(int data, Object object){
this.data =data;
this.object=object;
}
public int getData() {
return data;
}
public Object getObject() {
return object;
}
}
이벤트를 발생시켜야 이벤트 객체의 값을 받아볼 수 있는데, 이 기능은 ApplicationContext, ApplicationEventListener 가 가지고 있다.
ApplicationEventListener 의 pulblishEvent( Event ) 에 이벤트 클래스를 주고 데이터를 생성자로 주어, 이벤트를 발생시킨다.
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@Override
public void run(ApplicationArguments args) throws Exception {
// applicationEventPublisher.publishEvent(new MyEvent(this,100));
applicationEventPublisher.publishEvent(new MyEvent2(100,new Object()));
}
이벤트를 핸들링 하려면, 핸들러, 즉 이벤트 컨트롤러가 필요하다. 핸들러는 반드시 빈으로 등록되어야한다.
이벤트 핸들링 메서드에 @EventListner 에노테이션을 주어 이벤트를 핸들링 한다.
파라미터는 핸들링하려고하는 이벤트이다.
@Component
public class AnotherHandler {
@EventListener
public void handle(MyEvent2 myEvent2){
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+myEvent2.getObject());
}
}
기본적으로 퍼블리싱 되는 이벤트에 여러가지 핸들러를 동시에 적용시킬수 있는데, 이때 주의해야할 사항은 멀티스레딩이 아니라는 것이다
즉 순차적이다.
여기에 순번을 주려면, AOP에서 사용했었던 @Order 에노테이션으로 순번을 주면 된다고 한다.
@Component
public class AnotherHandler {
@EventListener
@Order(1)
public void handle(MyEvent2 myEvent2){
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+myEvent2.getObject());
}
@EventListener
@Order(2)
public void handle1(MyEvent2 myEvent){
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+myEvent.getObject());
}
}
이를 비동기적으로 이용하려면
이벤트 핸들링 메서드에 @Async 에노테이션을 붙이고 @Configuration 클래스에 @EnableAsync 에노테이션을 붙여야하며, 쓰레드 풀에서 돌기에 순번은 전혀 보장되지 못한다.
@Component
public class AnotherHandler {
@EventListener
@Async
public void handle(MyEvent2 myEvent2){
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+myEvent2.getObject());
}
@EventListener
@Async
public void handle1(MyEvent2 myEvent){
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+myEvent.getObject());
}
}
@SpringBootApplication
@EnableAsync
public class Demospring51Application {
public static void main(String[] args)
{
SpringApplication.run(Demospring51Application.class, args);
}
}
여기서 생각해봐야할 점은, 스프링에서 기본적으로 제공하는 ApplicationEvent 가 존재한다는 것이다.
ApplicationRefreshEvent 는 초기화 시점 , ApplicationClosedEvent 는 종료시점이다.
EventListener
@Async
/* @Order(Ordered.HIGHEST_PRECEDENCE+3)*/
public void handle(ContextRefreshedEvent event){
System.out.println(Thread.currentThread().toString());
System.out.println("ContextRefreshedEvent");
}
@EventListener
@Async
/* @Order(Ordered.HIGHEST_PRECEDENCE+3)*/
public void handle(ContextClosedEvent event){
System.out.println(Thread.currentThread().toString());
System.out.println("ContextClosedEvent");
}
생명주기 관련하여 추가할 것이 있을시, 사용해보고 싶다.
스프링 4.2 이전 버전이하에서는 이벤트 핸들러는 ApplicationListener 를 구현해야 했으며, 이벤트 객체는 ApplicationEvent 를 구현해야 했다.
@Component
public class MyEventHandler implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("이벤트 받았다. 데이터는 "+event.getData());
}
}
package me.soomin.demospring51;
import org.springframework.context.ApplicationEvent;
public class MyEvent extends ApplicationEvent {
private int data;
/**
* Create a new {@code ApplicationEvent}.
*
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
*/
public MyEvent(Object source) {
super(source);
}
public MyEvent(Object source,int data) {
super(source);
this.data = data;
}
public int getData() {
return data;
}
}
'springframework' 카테고리의 다른 글
o.s.w IoC 핵심기술. Resource 추상화 (0) | 2020.08.24 |
---|---|
o.s.w IoC 핵심기술. ResourceLoader (0) | 2020.08.23 |
springframeworko.s.w IoC 핵심기술. MessageSource (0) | 2020.08.21 |
o.s.w IoC 핵심기술. @PropertySource (0) | 2020.08.20 |
springframeworko.s.w IoC 핵심기술. @Profile (0) | 2020.08.20 |