ApplicationEventPublisher
ApplicationContext가 상속받는 또다른 인터페이스인 ApplicationEventPublisher 를 소개하겠습니다.
이 인터페이스는 옵저버 패턴의 구현체로
이벤트 기반의 프로그래밍을 할 때 유용합니다.
스프링 4.2 이전의 경우
이벤트를 발생시키기 위해서 이벤트 클래스를 선언하되
ApplicationEvent 를 상속하여 생성자를 오버라이딩 합니다.
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
이 이벤트는 Bean으로 등록되지 않고, 원하는 정보를 담아서 전달해주는 매개라고 생각하면 됩니다.
이벤트를 발생시키는 지점과 이벤트를 사용하는 지점이 다르기 때문에
발생 지점 -> 사용 지점으로 전달하기 위해선 어떤 매개가 필요한데
이벤트 객체가 그런 매개로서의 역할을 합니다.
이벤트를 Publish 하는 기능을 ApplicationEventPublisher 에서 가지고 있습니다.
메세지를 발생시키기 위해 ApplicationEventPublisher를 가져와서 이벤트를 발생시켜 봅니다.
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
ApplicationEventPublisher publisher;
@Override
public void run(ApplicationArguments args) throws Exception {
publisher.publishEvent(new MyEvent(this));
}
}
그럼 해당 이벤트를 받는 지점은 어디인가요?
ApplicationListener를 Bean으로 등록하여 사용합니다.
@Component
public class MyEventListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) {
System.out.println("이벤트 받았다잉");
}
}
전달받은 이벤트를 갖고 그 안에 들어있는 데이터를 꺼낸다던가, 특정 작업을 수행해주면 됩니다.
이렇게 하면 이벤트 기반 프로그래밍을 쉽게 할 수 있습니다.
스프링 4.2 이후
4.2 이후엔 ApplicationEvent를 상속하지 않고도 그냥 Event 객체를 선언하여 사용하면 됩니다.
public class MyEvent {
private Object source;
private String data;
public MyEvent(Object source, String data) {
this.source = source;
this.data = data;
}
}
Event 객체는 ApplicationEvent를 더이상 상속하지 않아도 되며
@Component
public class MyEventListener {
@EventListener
public void onApplicationEvent(MyEvent event) {
System.out.println("이벤트 받았다잉");
}
}
이벤트리스너 또한 ApplicationEventListener를 상속하지 않아도 됩니다.
대신 메소드 위에 @EventListener 어노테이션을 달아주시면 됩니다. (메소드 명도 마음대로)
만약 동일한 인자를 받는 이벤트리스너가 여러개 있는 경우엔 모두 실행됩니다.
만약 이벤트 리스너의 순서가 중요한 경우엔 @Order 어노테이션을 이용하면 됩니다.
Order 어노테이션에 넣는 값이 작을수록 우선순위가 높습니다.
만약 비동기적으로 작동시키려면 @Async 어노테이션을 이벤트 리스너에 추가합니다.
그런 경우엔 자연스럽게 Order가 의미 없게 됩니다.
@Async 어노테이션만 리스너에 붙인다고 해서 다른 쓰레드에서 비동기적으로 동작하는 것은 아닙니다.
Application 메인 클래스에 @EnableAsync 를 붙여주면 됩니다.
@SpringBootApplication
@EnableAsync
public class AutowiredApplication {
@EventListener
@Async
public void onApplicationEvent(MyEvent event) {
System.out.println(Thread.currentThread().toString());
System.out.println("이벤트 받았다잉");
}
ResourceLoader
리소스 로더는 인터페이스 이름이 암시하듯 리소스를 로딩해주는 인터페이스인데요
ApplicationContext가 이 기능을 상속해줍니다.
@Autowired
ResourceLoader resourceLoader;
@Override
public void run(ApplicationArguments args) throws Exception {
Resource resource = resourceLoader.getResource("classpath:test.txt");
System.out.println(resource.exists());
System.out.println(resource.getDescription());
String result = Files.readString(Path.of(resource.getURI()));
System.out.println(result);
}
단순히 리소스로더를 이용해서 특정 위치의 파일을 가져와서 읽어주는 예시입니다.
classpath의 default 위치는 resources 폴더이니 실제로 텍스트 파일을 생성할 때 resource 폴더에 추가해주세요.
'Java > Spring' 카테고리의 다른 글
[12] 스프링 프레임워크 핵심 - SPEL, Null Safety (0) | 2020.12.16 |
---|---|
[8] 스프링 프레임워크 핵심 - MessageSource (0) | 2020.12.14 |
[7] 스프링 프레임워크 핵심 - Environment, Profile, Property (0) | 2020.12.05 |
[6] 스프링 프레임워크 핵심 - Component Scan, Bean Scope (0) | 2020.12.05 |
[5] 스프링 프레임워크 핵심 - Autowired (0) | 2020.12.04 |
댓글