ApplicationEventPublisher 를 주입하고 publishEvent() 를 호출하여 이벤트를 발행할 수 있다.
ApplicationEventPublisherAware 인터페이스를 발행자 클래스가 구현하는 방식으로도 가능하다.
Spring Framework 4.2 부터 ApplicationEventPublisher 인터페이스는 모든 객체를 이벤트로 허용하는 publishEvent(Object event) 메서드에 대한 새로운 오버로드를 제공한다. 그러므로 더 이상 ApplicationEvent 클래스를 확장할 필요가 없다.
2.3. 수신자
수신자를 구현해보자. ApplicationListener 인터페이스만 구현하면 된다.
사용자 정의 이벤트가 제네릭 타입을 통해 매개변수화되어 onApplicationEvent() 메서드를 type-safe 하게 구성
3. 비동기 이벤트 처리
이벤트를 비동기로 처리해야 할 수도 있다.
ApplicationEventMulticaster 빈 설정을 통해 비동기로 구성시킬 수 있다.
수신자는 별도의 스레드에서 이벤트를 비동기적으로 처리하도록 설정된다.
4. 프레임워크에서 제공하는 이벤트
Spring의 ApplicationContext는 ContextRefreshedEvent, ContextStartedEvent, RequestHandledEvent 등 다양한 이벤트를 발생시킨다.
이러한 이벤트는 개발자가 애플리케이션의 수명 주기와 컨텍스트를 연결하고 필요한 경우 직접 구현한 로직을 추가할 수 있도록 옵션을 제공한다.
@Component
class CustomSpringEventPublisher(
val applicationEventPublisher: ApplicationEventPublisher,
) {
fun publishCustomEvent(message: String) {
println("Publishing custom event.")
val customSpringEvent = CustomSpringEvent(this, message)
applicationEventPublisher.publishEvent(customSpringEvent)
}
}
@Component
class CustomSpringEventListener : ApplicationListener<CustomSpringEvent> {
override fun onApplicationEvent(event: CustomSpringEvent) {
println("Received spring custom event - ${event.message}")
}
}
@Configuration
class AsynchronousSpringEventsConfig {
@Bean(name = ["applicationEventMulticaster"])
fun simpleApplicationEventMulticaster(): ApplicationEventMulticaster =
SimpleApplicationEventMulticaster()
.apply { setTaskExecutor(SimpleAsyncTaskExecutor()) }
}
@Component
class ContextRefreshedListener : ApplicationListener<ContextRefreshedEvent> {
override fun onApplicationEvent(event: ContextRefreshedEvent) {
println("Handling context refreshed event.")
}
}
@Component
class AnnotationDrivenEventListener {
@EventListener
fun handleContextStart(event: ContextStartedEvent) {
println("Handling context started event.")
}
}
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
class GenericSpringEvent<T>(
val what: T,
val success: Boolean
)
@Component
class GenericSpringEventListener : ApplicationListener<GenericSpringEvent<String>> {
override fun onApplicationEvent(event: GenericSpringEvent<String>) {
TODO("Not yet implemented")
}
}
@Component
class AnnotationDrivenEventListener {
@EventListener(condition = "#event.success")
fun handleSuccessful(event: GenericSpringEvent<String>) {
println("Handling generic event (conditional).")
}
}
@Component
class GenericSpringEventPublisher(
val applicationEventPublisher: ApplicationEventPublisher,
) {
fun publishEvent(message: String) {
println("Publishing generic event. ")
val genericEvent = GenericSpringEvent(message, true)
applicationEventPublisher.publishEvent(genericEvent)
}
}
@Component
class AnnotationDrivenEventListener {
@EventListener
fun handleCustomEvent(event: CustomSpringEvent): CustomSpringEvent2 {
println("Handling custom event.")
return CustomSpringEvent2("message")
}
@EventListener
fun handleCustomEvent2(event: CustomSpringEvent2) {
println("Handling custom event2.")
}
}
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
fun handleCustom(event: CustomSpringEvent) {
println("Handling event inside a transaction BEFORE COMMIT")
}