ApplicationContextEvent는 ApplicationContext의 생명 주기에 따라 발생시키는 이벤트입니다.
개발자가 스프링 이벤트를 직접 사용하는 경우 @EventListener와 함께 ApplicationEvent를 사용하지만, ApplicationContextEvent는 스프링 내부적으로 발행하는 이벤트이기 때문에 개발자가 직접 사용할 일은 희박합니다.
위와 같이 ApplicationContextEvent를 확장한 클래스는 다음과 같이 4종류가 존재합니다.
여기서 Started, Stopped의 경우 명시적으로 AbstractApplicationContext에서 stop(), start()를 명시적으로 호출해야 하기 때문에 잘 사용되지 않습니다.
그러므로 Refreshed, Closed 호출 시 이를 처리하는 Listener만 살펴보고 나머지는 단순히 어떤 상황에서 호출되는지만 확인하겠습니다.
스프링에서는 위와 같이 ApplicationContext에서 관리하고 있는 ApplicationEventMulticaster를 통해 이벤트를 발행합니다.
특별한 설정을 하지 않는 이상 SimpleApplicationEventMulticaster를 사용합니다.
만약 ApplicationContext에 ApplicationEventMulticaster를 초기화하지 않은 상태라면 earlyApplicationEvents에 컬렉션이 초기화된 상태가 됩니다.
그러므로 ApplicationContext 생명 주기에 의해 발생한 이벤트를 ApplicationContext에서 관리할 수 있습니다.
이렇게 저장한 earlyApplicationEvents는 AbstractApplicationContext.refresh()에서 onRefresh() 호출 후, finishBeanFactoryInitialization()으로 인해 빈 인스턴스를 생성하기 전 Listener를 등록하는 registerListeners()에서 발행됩니다.
이 시점에서는 ApplicationEventMulticaster가 초기화하므로, 그 직후 이벤트를 발행한다고 볼 수 있습니다.
ApplicationContext를 refresh할 때 발행하는 이벤트입니다.
ApplicationContext가 close되지 않았다면 계속 발행이 가능합니다.
다만, 일반적으로는 ApplicationContext.refresh()가 모두 수행된 이후에 단 한 번만 발행됩니다.
만약 애플리케이션 동작 도중 ApplicationContext의 설정(빈 구성 등)이 변경되는 경우에는 다시 ContextRefreshEvent가 발행될 수 있지만, 흔한 상황은 아니기 때문에 한 번만 수행한다고 봐도 무방합니다.
AbstractApplicationContext.refresh()를 모두 수행하고, 후처리를 수행하는 finishRefresh()에서 이벤트를 발행하고 있음을 확인할 수 있습니다.
ApplicationContext에 등록된 Listener 중 ContextRefreshedEvent 이벤트를 처리하는 Listener는 다음과 같습니다.
ApplicationContext.close()를 호출했을 때 발행하는 이벤트입니다.
이 이벤트가 발행되었다는 것은 ApplicationContext가 완전히 종료되었고, 재시작 할 수 없는 상태가 되었음을 의미합니다.
위와 같이 AbstractApplicationContext.doClose() 수행 시 이벤트를 발행한 뒤 나머지 작업을 수행하고 있음을 확인할 수 있습니다.
ApplicationContext가 중지(stopped)된 후, 명시적으로 AbstractApplicationContext.start()를 호출했을 때 발행되는 이벤트입니다.
명시적으로 AbstractApplicationContext.stop()이 호출된 이후에 명시적으로 AbstractApplicationContext.start()를 호출해야만 발행됩니다.
AbstractApplicationContext.start() 호출 시 발행됩니다.
동작 중인 ApplicationContext를 중지한 후 발행되는 이벤트입니다.
AbstractApplicationContext.stop() 호출 시 발행됩니다.