1.前言
SpringBoot应用在启动的时候会将配置类生成BeanDefinition并注入到容器中、启动Tomcat服务容器,那么当你执行kill -2 pid命令后,你是否知道应用做了哪些操作?如果不知道,请继续往下查看。
2.注册关闭钩子
当SpringBoot应用启动的时候会注册关闭钩子
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
// 注册关闭钩子
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
通过如上代码可以看到关闭钩子实际上就是一个线程任务
3.执行关闭操作
在启动的时候注册了关闭钩子,那么当执行kill -2 pid命令的时候就会调用注册的钩子,也就是doClose();方法
3.1 发布应用关闭事件
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
如果想在应用关闭的时候做一些资源释放操作,可以通过监听ContextClosedEvent事件来完成
3.2 调用Lifecycle的stop()方法
// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
调用所有实现Lifecycle接口的stop()方法,以WebServerGracefulShutdownLifecycle为例
@Override
public void stop(Runnable callback) {
this.running = false;
this.webServer.shutDownGracefully((result) -> callback.run());
}
private void doShutdown(GracefulShutdownCallback callback) {
// 1.获取所有的Connector
List<Connector> connectors = getConnectors();
// 2.关闭所有的Connector,使得Tomcat服务容器不在接收web请求
connectors.forEach(this::close);
try {
for (Container host : this.tomcat.getEngine().findChildren()) {
for (Container context : host.findChildren()) {
// 3.判断context是否处于激活状态,如果处于激活状态,进行循环判断,直到请求处理完成
while (isActive(context)) {
if (this.aborted) {
logger.info("Graceful shutdown aborted with one or more requests still active");
callback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);
return;
}
Thread.sleep(50);
}
}
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
logger.info("Graceful shutdown complete");
callback.shutdownComplete(GracefulShutdownResult.IDLE);
}
由此部分可以得知WebServerGracefulShutdownLifecycle主要用来实现应用的优雅停机,要求SpringBoot2.3及以上版本
3.3 调用Bean的destroy()方法
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
// Actually destroy the bean now...
if (bean != null) {
try {
bean.destroy();
}
catch (Throwable ex) {
}
}
}
遍历所有的Bean然后调用其实现的destroy();方法,以ThreadPoolTaskExecutor为例
@Override
public void destroy() {
shutdown();
}
public void shutdown() {
if (this.executor != null) {
// 关闭线程池
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();
}
else {
for (Runnable remainingTask : this.executor.shutdownNow()) {
cancelRemainingTask(remainingTask);
}
}
awaitTerminationIfNecessary(this.executor);
}
}
4. 总结
当执行kill -2 pid命令后,应用程序主要发布了ContextClosedEvent事件、调用Connector的close()方法不再接收web请求并等待处理中的请求执行完成、关闭线程池资源