/** * Class to be extended by all application events. Abstract as it * doesn't make sense for generic events to be published directly. * * @author Rod Johnson * @author Juergen Hoeller */ publicabstractclassApplicationEventextendsEventObject {
/** use serialVersionUID from Spring 1.2 for interoperability */ privatestaticfinallongserialVersionUID=7099057708183571937L;
/** System time when the event happened */ privatefinallong timestamp;
/** * Create a new ApplicationEvent. * @param source the object on which the event initially occurred (never {@code null}) */ publicApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); }
/** * Return the system time in milliseconds when the event happened. */ publicfinallonggetTimestamp() { returnthis.timestamp; }
/** * Base class for events raised for an {@code ApplicationContext}. * * @author Juergen Hoeller * @since 2.5 */ @SuppressWarnings("serial") publicabstractclassApplicationContextEventextendsApplicationEvent {
/** * Get the {@code ApplicationContext} that the event was raised for. */ publicfinal ApplicationContext getApplicationContext() { return (ApplicationContext) getSource(); }
}
Spring 容器(IOC 容器)有一个重要的方法 refresh 在 AbstractApplicationContext 类中,该方法用于加载或刷新配置(XML、配置文件等)的 Bean。执行该方法,如果已经有容器存在,则会销毁容器和已经存在的实例并重新实例化,类似于重启。
// Destroy already created singletons to avoid dangling resources. destroyBeans();
// Reset 'active' flag. cancelRefresh(ex);
// Propagate exception to caller. throw ex; }
finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
refresh 方法里有一个方法 finishRefresh。
1 2 3 4 5 6 7 8 9 10 11 12 13
protectedvoidfinishRefresh() { // Initialize lifecycle processor for this context. initLifecycleProcessor();
// Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh();
protectedvoidpublishEvent(Object event, ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); }
// Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = newPayloadApplicationEvent<Object>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType(); } }
// Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { // 这里是重点 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); }
// Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
// Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); }
// Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
------------------- Spring refreshed --------------------- ------------------- Spring started --------------------- ------------------- Spring stopped ---------------------
通过 ClassPathXmlApplicationContext 来加载配置文件初始化容器上下文,在容器调用 start 方法时,事件 ContextStartedEvent 发布,容器调用 stop 方法时,事件 ContextStoppedEvent 发布。但是常用的业务场景是我们需要在容器加载完成后执行一些操作,这时候我们常使用 ContextRefreshEvent 事件对象。但是在使用它的时候需要注意,尤其是我们使用了 Spring 和 Spring MVC,因为父子容器的原因,系统中会存在两个容器,一个是 Root Application Context,另一个就是我们配置的 Spring MVC 的容器(作为 ROOT 的子容器)。这个时候 refresh 会被调用两次,同样监听器里的 onApplicationEvent 也会执行两次,避免这种情况就需要在自定义的监听器里修改代码: