
스프링 이벤트는 스프링에서 제공하는 메커니즘으로 컴포넌트간 느슨한 결합을 통해 상호작용할 수 있는 방법이다.
스프링 이벤트는 옵저버 패턴을 기반을 두고 있다. 이는 publisher와 subscriber가 있으며, publisher의 상태가 변경되면, 해당 변경에 대해 subscriber에게 subject 객체를 전달하는 디자인 패턴이다.
스프링에서는 ApplicationEvent 클래스의 인스턴스를 통해 이벤트를 발생한다.
스프링 이벤트는 다음과 같은 core 클래스들을 제공한다.
위 클래스들을 통해 스프링 내부에서 이벤트 기반 프로그래밍을 가능하게 만든다.
스프링 이벤트 메커니즘을 통해 스프링 내부의 컴포넌트들은 서로의 존재를 모르더라도 상호작용할 수 있다.
위 클래스들을 기반으로 이벤트의 흐름을 나타내면 다음과 같다.

그러면 core 클래스들의 코드를 살펴봐보자
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public ApplicationEvent(Object source, Clock clock) {
super(source);
this.timestamp = clock.millis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
ApplicationEvent는 스프링 이벤트에서 publish, consume에서 사용되는 기반 클래스이다.
또한 ApplicationEvent의 서브 클래스가 필요한 정보들을 초기화할 수 있는 생성자를 제공한다.
위 코드에서는 인스턴스 생성 시간과 함께, 이벤트 객체를 담을 수 있다.
또한 ApplicationEvent의 확장을 통해 특정 이벤트에서 사용하는 이벤트 객체를 만들 수 있다.

위 이미지에서는 ApplicationEvent의 서브 클래스들을 확인할 수 있다.
스프링 부트는 스프링을 간단하게 설정하며 실행할 수 있도록 도와주는 기능을 제공한다. 이때 스프링 이벤트를 기본적으로 설정되어 있으며, 여러 이벤트를 제공한다.
스프링 애플리케이션이 실행되면 EventPublishingRunListener 클래스를 통해 이벤트를 발행한다.
EventPublishingRunListener 애플리케이션으로부터 현재 상태가 담긴 이벤트를 수신하면, SimpleApplicationEventMulticaster를 통해 이벤트를 전파한다.
class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
}
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
this.multicastInitialEvent(new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
public void contextPrepared(ConfigurableApplicationContext context) {
this.multicastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
public void contextLoaded(ConfigurableApplicationContext context) {
ApplicationListener listener;
for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
listener = (ApplicationListener)var2.next();
if (listener instanceof ApplicationContextAware contextAware) {
contextAware.setApplicationContext(context);
}
}
this.multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all the context's listeners instead
if (context instanceof AbstractApplicationContext abstractApplicationContext) {
for (ApplicationListener<?> listener : abstractApplicationContext.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
private void multicastInitialEvent(ApplicationEvent event) {
this.refreshApplicationListeners();
this.initialMulticaster.multicastEvent(event);
}
private void refreshApplicationListeners() {
this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);
}
}
EventPublishingRunListener는 SpringApplicationRunListener 인터페이스를 구현한다. 이 인터페이스는 스프링 애플리케이션 실행 과정에서의 호출할 수 있는 메소드를 제공한다.
EventPublishingRunListener의 생성자에서 볼 수 있듯, SimpleApplicationEventMulticaster 인스턴스를 생성한다.
스프링 이벤트를 사용할 때 다음과 같은 용도로 사용할 수 있다.