ApplicationContext
에 대한 상위 인터페이스 역할 수행💡 이벤트 기반 프로그래망?
Event 객체가 있고, Event 객체를 다루는 EventHandler 객체가 존재하는 것
Observer Pattern
의 구현체💡 Observer Pattern
- 하나의 객체가 상태를 변경하면 모든 종속된 항목이 자동으로 알림을 받고 업데이트되도록 객체 간의 일대다 종속성을 정의하는 것
- 여러 관찰자 개체가 이벤트를 볼 수 있도록 하는 게시/구독 패턴의 하위 집합
- 개체가 다른 개체에 메시지를 알릴 수 있어야 하고 이러한 개체들이 밀접하게 결합되는 것을 원하지 않을 때 사용
ApplicationContext
인터페이스에 상속되어 있음ApplicationContext
구현체에서 접근 가능publishEvent
메소드 제공ApplicationEvent
를 상속받아 사용자가 원하는 데이터를 입력받도록 구현<E extends ApplicationEvent>
ApplicationListener
를 구현하여 onApplicationEvent(E)
메소드 구현💡
onApplicationEvent(E)
- Spring에서 제공하는
ApplicationEventPublisher
에서 특정 이벤트를 publish하는 경우 자동으로 실행- 매개변수로 전달되는 event를 이용해 원하는 작업 처리 구현 가능
ApplicationEvent
상속받은 클래스를 지정하여 컴파일 타임에 형 안정성을 보장받을 수 있음public class ExampleEvent extends ApplicationEvent {
private int data;
public ExampleEvent(Object source, int data) {
super(source);
this.data = data;
}
public int getData() {
return data;
}
}
@Component
public class ExampleEventHandler implements ApplicationListener<ExampleEvent> {
@Override
public void onApplicationEvent(ExampleEvent event) {
System.out.println("이벤트 전달 받음, data = " + event.getData());
}
}
@Component
추가@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationEventPublisher eventPublisher;
//ApplicationContext ctx;
@Override
public void run(ApplicationArguments args) throws Exception {
eventPublisher.publishEvent(new ExampleEvent(this, 100));
}
}
ApplicationEventPublisher
는 ApplicationContext
에 의해 구현publishEvent()
메소드 호출run()
메소드가 실행되어 이벤트 발생ExampleEventHandler
클래스를 실행시켜 콘솔에 결과 출력ApplicationContext
타입도 주입 가능Spring 4.2부터는 POJO 구조로, Spring 코드 없이 이벤트 기반의 프로그래밍 가능
public class ExampleEvent {
private int data;
public ExampleEvent(Object source, int data) {
super(source);
this.data = data;
}
public int getData() {
return data;
}
}
ApplicationEvent
상속 x@Component
public class ExampleEventHandler {
@EventListener
public void onApplicationEvent(ExampleEvent event) {
System.out.println("이벤트 전달 받음, data = " + event.getData());
}
}
ApplicationListener
을 구현하는 대신 @EventListener
어노테이션 사용@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationEventPublisher eventPublisher;
@Override
public void run(ApplicationArguments args) throws Exception {
eventPublisher.publishEvent(new ExampleEvent(this, 100));
}
}
같은 이벤트를 다루는 이벤트 핸들러가 여러개인 경우 순차적으로 진행되며, 실행 순서는 알 수 없다.
@Order
이용@Order
어노테이션을 사용하여 순서 지정HIGHEST_PRECEDENCE
: 가장 높은 우선순위 (=Integer.MIN_VALUE
)LOWEST_PRECEDENCE
: 가장 낮은 우선순위 (=Integer.MAX_VALUE
)@Component
public class OrderHandler {
@EventListener
@Order(Ordered.HIGHEST_PRECEDENCE + 1) //설정하는 값이 클수록 우선순위 ↓
public void onApplicationEvent(ExampleEvent event) {
System.out.println("이벤트를 전달 받음, data = " + event.getMessge());
}
}
💡 동기와 비동기
- 동기(Sync)
- 어떠한 작업이 순차적으로 실행
- 요청 시 결과 반환을 기다려야 함
- 비동기(Async)
- 어떠한 작업이 동시에 실행
- 요청과 결과 반환이 동시에 일어나지 않음
@Async
지정@Component
public class ExampleEventHandler{
@EventListener
@Async
public void onApplicationEvent(ExampleEvent event) {
System.out.println("이벤트 전달 받음, data = " + event.getData());
}
@EnableAsync
지정@SpringBootApplication
@EnableAsync
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
이벤트 | 설명 |
---|---|
ContextRefreshedEvent | ApplicationContext 를 초기화하거나 리프레시 했을 때 발생 |
ContextStartedEvent | ApplicationContext 를 start()하여 라이프 사이클 빈들이시작 신호를 받은 시점에 발생 |
ContextStoppedEvent | ApplicationContext 를 stop()하여 라이프 사이클 빈들이정지 신호를 받은 시점에 발생 |
ContextClosedEvent | ApplicationContext 를 close()하여 싱글톤 빈이 소멸되는 시점에 발생(실행 중인 스프링을 중지하면 발생) |
RequestHandledEvent | HTTP 요청을 처리했을 때 발생 |
@Component
public class ExampleEventHandler {
@EventListener
@Async
public void handle(ContextRefreshedEvent event){
System.out.println("Refresh");
}
@EventListener
@Async
public void handle(ContextStartedEvent event){
System.out.println("Started");
}
@EventListener
@Async
public void handle(ContextStoppedEvent event){
System.out.println("Stopped");
}
@EventListener
@Async
public void handle(ContextClosedEvent event){
System.out.println("Closed");
}
}
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationContext ctx;
//ApplicationEventPublisher eventPublisher;
@Override
public void run(ApplicationArguments args) throws Exception {
ctx.publishEvent(new ExampleEvent(this, 100));
((ConfigurableApplicationContext)ctx).start();
((ConfigurableApplicationContext)ctx).stop();
((ConfigurableApplicationContext)ctx).close();
}
📖 참고
- Interface ApplicationEventPublisher
- Spring - IoC 컨테이너의 기능 - 4 (ApplicationEventPublisher 란?)
- Observer Pattern with Spring Events
- [Spring] ApplicationEventPublisher
- Interface Ordered
- Spring @Order 로 Bean 순서 정의하기
- [Spring] ApplicationEventPublisher를 이용한 이벤트 프로그래밍
- [Spring] ApplicationEventPublisher를 통한 스프링 이벤트 처리(ApplicationEventPublisher, Spring Event Processing)
- Spring - ApplicationEventPublisher
- [CS] 동기와 비동기 , 이벤트 기반 프로그래밍