Spring容器启动过程中,针对启动的各个阶段定义了对应的内建事件:
ContextRefreshedEvent在ConfigurableApplicationContext.refresh() 完成时触发,源码如下:
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {
...
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
// 1.初始化事件广播器
this.initApplicationEventMulticaster();
this.onRefresh();
// 2.注册ApplicationListener
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
// 3.ContextRefreshedEvent
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
// 发布事件
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
}
ContextStartedEvent 和 ContextStoppedEvent,比较罕见,两者分别在AbstractApplicationContext.start() 和AbstractApplicationContext.stop()方法中发布:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
...
// 启动:ContextStartedEvent
@Override
public void start() {
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}
// 关闭:ContextStoppedEvent
@Override
public void stop() {
getLifecycleProcessor().stop();
publishEvent(new ContextStoppedEvent(this));
}
...
}
在绝大多数场景中,start()和stop()不会被调用,然而并不意味着他们没有存在的价值:
通过控制ApplicationContext启停最终能触发LifecycleBean的启停:
// 自动组件接口:Lifecycle
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
public interface LifecycleProcessor extends Lifecycle {
// 通知自动组件启动
void onRefresh();
// 通知自动组件关闭
void onClose();
}
对应这两个事件实际的应用,可以在SpringCloud resume 和pause Endpoint中找到
@Endpoint(id = "restart", enableByDefault = false)
public class RestartEndpoint implements ApplicationListener<ApplicationPreparedEvent> {
...
// Spring 上下文
private ConfigurableApplicationContext context;
public PauseEndpoint getPauseEndpoint() {
return new PauseEndpoint();
}
public ResumeEndpoint getResumeEndpoint() {
return new ResumeEndpoint();
}
@Endpoint(id = "pause")
public class PauseEndpoint {
@WriteOperation
public Boolean pause() {
if (isRunning()) {
doPause();
return true;
}
return false;
}
}
@Endpoint(id = "resume")
@ConfigurationProperties("management.endpoint.resume")
public class ResumeEndpoint {
@WriteOperation
public Boolean resume() {
if (!isRunning()) {
doResume();
return true;
}
return false;
}
}
// 重启,调用close()
public synchronized ConfigurableApplicationContext doRestart() {
if (this.context != null) {
if (this.integrationShutdown != null) {
this.integrationShutdown.stop(this.timeout);
}
this.application.setEnvironment(this.context.getEnvironment());
close();
// If running in a webapp then the context classloader is probably going to
// die so we need to revert to a safe place before starting again
overrideClassLoaderForRestart();
this.context = this.application.run(this.args);
}
return this.context;
}
...
// 触发ContextStoppedEvent
public synchronized void doPause() {
if (this.context != null) {
this.context.stop();
}
}
// 触发ContextStartedEvent
public synchronized void doResume() {
if (this.context != null) {
this.context.start();
}
}
...
}
ContextCloseEvent事件与ContextRefreshedEvent正好相反,它有
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
// 触发ContextClosedEvent
protected void doClose() {
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
this.active.set(false);
}
}
}
自定义Spring事件,继承ApplicationEvent即可:
public class MyApplicationEvent extends ApplicationEvent {
public MyApplicationEvent(String source) {
super(source);
}
}
事件的发布听过ApplicationEventPublisher.publishEvent(), 而Application默认实现了ApplicationEventPublisher接口,所以自定义事件,可以直接通过Spring Context发布:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
}