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 小結
好啦,本節下線的時機就看到這裡,有理解不對的地方歡迎指正。