ApplicationEventPublisher
- ApplicationEventPublisher는 Spring의 ApplicationContext가 상속하는 인터페이스 중 하나.
- 스프링 이벤트 프로그래밍에 필요한 인터페이스
- 옵저버 패턴 구현체
1. ApplicationEvent 상속받은 Event 선언
package com.bpkim.demospring51;
import org.springframework.context.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;
}
}
2. 이벤트 발생 시키기
package com.bpkim.demospring51;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationEventPublisher publishEvent;
@Override
public void run(ApplicationArguments args) throws Exception{
publishEvent.publishEvent(new MyEvent(this, 100));
}
}
3. 이벤트 핸들러 생성
package com.bpkim.demospring51;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventHandler implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent myEvent) {
System.out.println("이벤트 받았다. 데이터는 "+ myEvent.getData());
}
}
- 실행
*** 스프링 4.2 부터는 ApplicationEvent을 상속 받지 않고 Event 를 만들 수 있고,
ApplicationListener를 상속하지 않고 핸들러를 만들 수 있다.
핸들러를 만들때는 핸들러 함수에 @EventLisiener를 이용해 빈 메소드에등로록 하여 사용한다.
1. 이벤트
- ApplicationEvent 상속제거
스프링 소스가 들어가있지 않은 비 침투성으로 스프링이 추구하는 방향!!
package com.bpkim.demospring51;
public class MyEvent {
private int data;
private Object source;
public MyEvent(Object source, int data) {
this.source = source;
this.data = data;
}
public int getData() {
return data;
}
}
2. 핸들러
- ApplicationListener 를 상속하여 특정 함수를 구현하지 않고 핸들러 함수에 @EventListener 를 이용하여 사용
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventHandler{
@EventListener
public void handler(MyEvent myEvent) {
System.out.println("이벤트 받았다. 데이터는 "+ myEvent.getData());
}
}
핸들러 여러개 등록
1. 핸들러 함수 추가
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class AnotherHandler {
@EventListener
public void handler(MyEvent myEvent) {
System.out.println("Another "+ myEvent.getData());
}
}
- 실행 결과
핸들러는 순차적으로 실행되나 어느것이 먼저 실행되는지는 모른다.
@Order 를 이용하여 우선순위를 정할 수 있다.
1. 핸들러 우선순위 정하기
- MyEventHandler의 우선순위를 우선 하기
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
public class MyEventHandler{
@EventListener
@Order(Ordered.HIGHEST_PRECEDENCE)
public void handler(MyEvent myEvent) {
System.out.println("이벤트 받았다. 데이터는 "+ myEvent.getData());
}
}
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
public class AnotherHandler {
@EventListener
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
public void handler(MyEvent myEvent) {
System.out.println("Another "+ myEvent.getData());
}
}
- 실행결과
순서가 바뀌었다.
비동기적 이벤트 처리
1. EventListener 에 @Async 사용
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class MyEventHandler{
@EventListener
@Async
public void handler(MyEvent myEvent) {
System.out.println(Thread.currentThread().toString());
System.out.println("이벤트 받았다. 데이터는 "+ myEvent.getData());
}
}
package com.bpkim.demospring51;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class AnotherHandler {
@EventListener
@Async
public void handler(MyEvent myEvent) {
System.out.println(Thread.currentThread().toString());
System.out.println("Another "+ myEvent.getData());
}
}
2. main 함수가 있는 클래스에 @EnableAsync 선언
package com.bpkim.demospring51;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class Demospring51Application {
public static void main(String[] args) {
SpringApplication.run(Demospring51Application.class, args);
}
}
- 실행결과
Async 설정 전 : main 스레드에서 실행되고 있다.
Async 설정 후 : 메인 스레드가 아닌 스레드에서 실행되고 있다.
스프링이 기본으로 제공하는 이벤트 처리 핸들러 사용 해보기
- ContextRefreshedEvent : ApplicationContext 초기화 시 발생
- ContextStartedEvent : ApplicationContext를 start() 하여 라이프사이클 빈들이 시작신홀르 받은 시점에 발생
- ContextStoppedEvent : ApplicationContext를 stop() 하여 라이프사이클 빈들이 정지신호를 받은 시점에 발생
- ContextClosedEvent : ApplicationContext를 close() 하여 싱글톤 빈 소멸되는 시점에 발생
- RequestHandledEvent : HTTP 요청을 처리했을 때 발생.
1. 핸들러 선언
package com.bpkim.demospring51;
import org.springframework.context.event.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Component
public class MyEventHandler{
@EventListener
@Async
public void handler(MyEvent myEvent) {
System.out.println(Thread.currentThread().toString());
System.out.println("이벤트 받았다. 데이터는 "+ myEvent.getData());
}
@EventListener
@Async
public void handler(ContextRefreshedEvent event) {
System.out.println(Thread.currentThread().toString());
System.out.println("ContextRefreshedEvent ");
}
@EventListener
@Async
public void handler(ContextClosedEvent event) {
System.out.println(Thread.currentThread().toString());
System.out.println("ContextClosedEvent ");
}
}
- 실행결과
'개발 > Spring' 카테고리의 다른 글
Resource 추상화 (0) | 2021.04.22 |
---|---|
Ioc 컨테이너 - ResourceLoader (0) | 2021.04.22 |
IoC - MessageSource (0) | 2021.04.11 |
IoC - Environment - 프로퍼티 (0) | 2021.04.11 |
IoC - Environment - 프로파일 (0) | 2021.04.10 |