【SpringBoot】服务对注册中心的下线时机

1  前言

上节我们主要看了下服务启动的注册时机,可以看到它最后的落点是在实例化 DiscoveryClient 的时候进行服务的注册,看完启动注册,那么我们本节就看看当服务关闭时候的一个下线时机以及过程。

当然服务关闭也分情况,比如我能想到的直接暴力关闭类似 kill -9,柔和优雅关闭的类似 kill -15,我们本节主要看柔和关闭的情况。

2  下线时机

服务的下线时机,我看了下大概分为两个地方,但是都是由同一个入口进来的。

同一个入口就是我们 SpringBoot 服务启动的时候,刷新上下文里注册的关闭钩子函数,它会在 JVM 退出的时候,来得到执行。

两个地方:

(1)EurekaAutoServiceRegistration 实现了 SmartLifecycle 生命周期的接口,stop 方法会得到执行

(2)DiscoveryClient 的 destoryMethod = "shutdown" 销毁的时候得到执行

2.1  一个入口

// ###SpringApplication
private void refreshContext(ConfigurableApplicationContext context) {
    // 上下文的刷新
    refresh(context);
    // 注册关闭钩子
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}
// ### AbstractApplicationContext
@Override
public void registerShutdownHook() {
    if (this.shutdownHook == null) {
        // No shutdown hook registered yet.
        this.shutdownHook = new Thread() {
            @Override
            public void run() {
                synchronized (startupShutdownMonitor) {
                    doClose();
                }
            }
        };
        Runtime.getRuntime().addShutdownHook(this.shutdownHook);
    }
}
// ###
protected void doClose() {
    // Check whether an actual close attempt is necessary...
    if (this.active.get() && this.closed.compareAndSet(false, true)) {
        if (logger.isDebugEnabled()) {
            logger.debug("Closing " + this);
        }
        if (!NativeDetector.inNativeImage()) {
            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.
        if (this.lifecycleProcessor != null) {
            try {
                // 两个地方之一 生命周期的关闭是在这里执行的
                this.lifecycleProcessor.onClose();
            }
            catch (Throwable ex) {
                logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
            }
        }
        // 销毁bean Destroy all cached singletons in the context's BeanFactory. 两个地方之二 Bean的销毁是在这里执行的
        destroyBeans();
        // 关闭bean工厂 Close the state of this context itself.
        closeBeanFactory();
        // 这里SpringBoot 用于关闭web容器比如停止掉tomcat Let subclasses do some final clean-up if they wish...
        onClose();
        // Reset local application listeners to pre-refresh state.
        if (this.earlyApplicationListeners != null) {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }
        // Switch to inactive.
        this.active.set(false);
    }
}

2.2  两个地方

(1)EurekaAutoServiceRegistration 实现了 SmartLifecycle 生命周期的接口,stop 方法会得到执行

// ### EurekaAutoServiceRegistration
public void stop() {
    this.serviceRegistry.deregister(this.registration);
    this.running.set(false);
}

(2)DiscoveryClient 的 destoryMethod = "shutdown" 销毁的时候得到执行

// ### CloudEurekaClient
// public class CloudEurekaClient extends DiscoveryClient
@Bean(
    destroyMethod = "shutdown"
)
@ConditionalOnMissingBean(
    value = {EurekaClient.class},
    search = SearchStrategy.CURRENT
)
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
    return new CloudEurekaClient(manager, config, this.optionalArgs, this.context);
}

日志信息:

最后画个图,捋一下思路:

3  小结

好啦,本节下线的时机就看到这里,有理解不对的地方欢迎指正。

posted @ 2024-06-27 12:08  酷酷-  阅读(19)  评论(0编辑  收藏  举报