摘要:除了,還有十余種,有的是特定操作,比如轉(zhuǎn)儲(chǔ)內(nèi)存日志有的是信息展示,比如顯示應(yīng)用健康狀態(tài)。
前言
隨著線上應(yīng)用逐步采用 SpringBoot 構(gòu)建,SpringBoot應(yīng)用實(shí)例越來(lái)多,當(dāng)線上某個(gè)應(yīng)用需要升級(jí)部署時(shí),常常簡(jiǎn)單粗暴地使用 kill 命令,這種停止應(yīng)用的方式會(huì)讓應(yīng)用將所有處理中的請(qǐng)求丟棄,響應(yīng)失敗。這樣的響應(yīng)失敗尤其是在處理重要業(yè)務(wù)邏輯時(shí)需要極力避免的,那么有什么更好的方式來(lái)平滑地關(guān)閉 SpringBoot 應(yīng)用呢?那就通過(guò)本文一起來(lái)探究吧。(本文主要針對(duì)基于Spring Boot 內(nèi)嵌 Tomcat 容器作為 Web 服務(wù)的應(yīng)用)
定制 Tomcat Connector 行為本文示例代碼可以通過(guò)下面?zhèn)}庫(kù)地址獲?。?/p>
springboot-shutdown:https://github.com/wrcj12138a...
環(huán)境支持:
JDK 8
SpringBoot 2.1.4
Maven 3.6.0
要平滑關(guān)閉 Spring Boot 應(yīng)用的前提就是首先要關(guān)閉其內(nèi)置的 Web 容器,不再處理外部新進(jìn)入的請(qǐng)求。為了能讓應(yīng)用接受關(guān)閉事件通知的時(shí)候,保證當(dāng)前 Tomcat 處理所有已經(jīng)進(jìn)入的請(qǐng)求,我們需要實(shí)現(xiàn) TomcatConnectorCustomizer 接口,這個(gè)接口的源碼十分簡(jiǎn)單,從注釋可以看出這是實(shí)現(xiàn)自定義 Tomcat Connector 行為的回調(diào)接口:
這里如果小伙伴對(duì) Connector 不太熟悉,我就簡(jiǎn)單描述下:Connector 屬于 Tomcat 抽象組件,功能就是用來(lái)接受外部請(qǐng)求,以及內(nèi)部傳遞,并返回響應(yīng)內(nèi)容,是Tomcat 中請(qǐng)求處理和響應(yīng)的重要組件,具體實(shí)現(xiàn)有 HTTP Connector 和 AJP Connector。
通過(guò)定制 Connector 的行為,我們就可以允許在請(qǐng)求處理完畢后進(jìn)行 Tomcat 線程池的關(guān)閉,具體實(shí)現(xiàn)代碼如下:
上述代碼定義的 TIMEOUT 變量為 Tomcat 線程池延時(shí)關(guān)閉的最大等待時(shí)間,一旦超過(guò)這個(gè)時(shí)間就會(huì)強(qiáng)制關(guān)閉線程池,也就無(wú)法處理所有請(qǐng)求了,我們通過(guò)控制 Tomcat 線程池的關(guān)閉時(shí)機(jī),來(lái)實(shí)現(xiàn)優(yōu)雅關(guān)閉 Web 應(yīng)用的功能。另外需要注意的是我們的類 CustomShutdown 實(shí)現(xiàn)了 ApplicationListener 接口,意味著監(jiān)聽(tīng)著 Spring 容器關(guān)閉的事件,即當(dāng)前的 ApplicationContext 執(zhí)行 close 方法。
內(nèi)嵌 Tomcat 添加 Connector 回調(diào)有了定制的 Connector 回調(diào),我們需要在啟動(dòng)過(guò)程中添加到內(nèi)嵌的 Tomcat 容器中,然后等待執(zhí)行。那這一步又是如何實(shí)現(xiàn)的呢,可以參考下面代碼:
這里的 TomcatServletWebServerFactory 是 Spring Boot 實(shí)現(xiàn)內(nèi)嵌 Tomcat 的工廠類,類似的其他 Web 容器,也有對(duì)應(yīng)的工廠類如 JettyServletWebServerFactory,UndertowServletWebServerFactory。他們共同的特點(diǎn)就是繼承同個(gè)抽象類 AbstractServletWebServerFactory,提供了 Web 容器默認(rèn)的公共實(shí)現(xiàn),如應(yīng)用上下文設(shè)置,會(huì)話管理等。
如果我們需要定義Spring Boot 內(nèi)嵌的 Tomcat 容器時(shí),就可以使用 TomcatServletWebServerFactory 來(lái)進(jìn)行個(gè)性化定義,例如下方為官方文檔提供自定示例:
好了說(shuō)回正題,我們這里使用 addConnectorCustomizers 方法將自定義的 Connector 行為添加到內(nèi)嵌的Tomcat 之上,為了查看加載效果,我們可以在 Spring Boot 程序啟動(dòng)后從容器中獲取下webServerFactory 對(duì)象,然后觀察,在它的 tomcatConnectorCustomizers 屬性中可以看到已經(jīng)有了 CustomeShutdown 對(duì)象。
開(kāi)啟 Shutdown Endpoint到目前讓內(nèi)嵌 Tomcat 容器平穩(wěn)關(guān)閉的操作已經(jīng)完成,接下來(lái)要做的就是如何關(guān)閉主動(dòng)關(guān)閉 Spring 容器了,除了常規(guī)Linux 命令 Kill,我們可以利用 Spring Boot Actuator 來(lái)實(shí)現(xiàn)Spring 容器的遠(yuǎn)程關(guān)閉,怎么實(shí)現(xiàn)繼續(xù)看
Spring Boot Actuator 是 Spring Boot 的一大特性,它提供了豐富的功能來(lái)幫助我們監(jiān)控和管理生產(chǎn)環(huán)境中運(yùn)行的 Spring Boot 應(yīng)用。我們可以通過(guò) HTTP 或者 JMX 方式來(lái)對(duì)我們應(yīng)用進(jìn)行管理,除此之外,它為我們的應(yīng)用提供了審計(jì),健康狀態(tài)和度量信息收集的功能,能幫助我們更全面地了解運(yùn)行中的應(yīng)用。
Actuator, ["?kt???e?t?] 中文翻譯過(guò)來(lái)就是制動(dòng)器,這是一個(gè)制造業(yè)的術(shù)語(yǔ),指的是用于控制某物的機(jī)械裝置。
在 Spring Boot Actuator 中也提供控制應(yīng)用關(guān)閉的功能,所以我們要為應(yīng)用引入 Spring Boot Actuator,具體方式就是要將對(duì)應(yīng)的 starter 依賴添加到當(dāng)前項(xiàng)目中,以 Maven 項(xiàng)目為例:
Spring Boot Actuator 采用向外部暴露 Endpoint (端點(diǎn))的方式來(lái)讓我們與應(yīng)用進(jìn)行監(jiān)控和管理,引入 spring-boot-starter-actuator 之后,我們就需要啟用我們需要的 Shutdown Endpoint,在配置文件 application.properties 中,設(shè)置如下
第一行表示啟用 Shutdown Endpoint ,第二行表示向外部以 HTTP 方式暴露所有 Endpoint,默認(rèn)情況下除了 Shutdown Endpoint 之外,其他 Endpoint 都是啟用的。
除了 Shutdown Endpoint,Actuator Endpoint 還有十余種,有的是特定操作,比如 heapdump 轉(zhuǎn)儲(chǔ)內(nèi)存日志;有的是信息展示,比如 health 顯示應(yīng)用健康狀態(tài)。具體所有 Endpoint 信息可以參見(jiàn)官方文檔-53. Endpoints 一節(jié)。
到這里我們的前期配置工作就算完成了。當(dāng)啟動(dòng)應(yīng)用后,就可以通過(guò)POST 方式請(qǐng)求對(duì)應(yīng)路徑的 http://host:port/actuator/shutdown 來(lái)實(shí)現(xiàn)Spring Boot 應(yīng)用遠(yuǎn)程關(guān)閉,是不是很簡(jiǎn)單呢。
模擬測(cè)試這里為了模擬測(cè)試,我們首先模擬實(shí)現(xiàn)長(zhǎng)達(dá)10s 時(shí)間處理業(yè)務(wù)的請(qǐng)求控制器 BusinessController,具體實(shí)現(xiàn)如下:
用 Thread.sleep 來(lái)阻塞當(dāng)前請(qǐng)求線程,模擬業(yè)務(wù)處理,在此同時(shí)用 HTTP 方式訪問(wèn) Shutdown Endpoint 試圖關(guān)閉應(yīng)用,可以通過(guò)觀察控制臺(tái)日志看是否應(yīng)用是否會(huì)完成請(qǐng)求的處理后才真正進(jìn)行關(guān)閉。
首先用 curl 命令模擬發(fā)送業(yè)務(wù)請(qǐng)求:
然后在業(yè)務(wù)處理中,直接發(fā)送請(qǐng)求 actuator/shutdown,嘗試關(guān)閉應(yīng)用,同樣采用 curl 方式:
actuator/shutdown 請(qǐng)求發(fā)送后會(huì)立即返回響應(yīng)結(jié)果,但應(yīng)用并不會(huì)停止:
最后看下控制臺(tái)的日志輸出順序:
可以看出在發(fā)送業(yè)務(wù)請(qǐng)求之后立刻發(fā)送關(guān)閉應(yīng)用的請(qǐng)求,并不會(huì)立即將應(yīng)用停止,而是在請(qǐng)求處理完畢之后,就是阻塞的 10s 后應(yīng)用開(kāi)始退出,這樣可以保證已經(jīng)接收到的請(qǐng)求能返回正常響應(yīng), 而關(guān)閉請(qǐng)求之后再進(jìn)入的請(qǐng)求都不會(huì)被處理,到這里我們優(yōu)雅關(guān)閉 Spring Boot 程序的操作就此實(shí)現(xiàn)了。
實(shí)現(xiàn)自動(dòng)化由于 Spring Boot 提供內(nèi)嵌 Web 容器的便利性,我們經(jīng)常將程序打包成 jar 然后發(fā)布。通常應(yīng)用的啟動(dòng)和關(guān)閉操作流程是固定且重復(fù)的,本著 Don"t Repeat Yourself 原則,我們有必要將這個(gè)操作過(guò)程自動(dòng)化,將關(guān)閉和啟用的 SpringBoot應(yīng)用的操作寫成 shell 腳本,以避免出現(xiàn)人為的差錯(cuò),并且方便使用,提高操作效率。下面是我針對(duì)示例程序所寫的程序啟動(dòng)腳本:(具體腳本可在示例項(xiàng)目查看)
有了腳本,我們可以直接通過(guò)命令行方式平滑地更新部署 Spring Boot 程序,效果如下:
總結(jié)本文主要探究了如何對(duì)基于Spring Boot 內(nèi)嵌 Tomcat 的 Web 應(yīng)用進(jìn)行平滑關(guān)閉的實(shí)現(xiàn),如果采用其他 Web 容器也類似方式,希望這邊文章有所幫助,若有錯(cuò)誤或者不當(dāng)之處,還請(qǐng)大家批評(píng)指正,一起學(xué)習(xí)交流。
參考Graceful Shutdown Spring Boot Applications:https://blog.marcosbarbero.co...
Shutdown a Spring Boot Application:https://www.baeldung.com/spri...
官方文檔-53. Endpoints:https://docs.spring.io/spring...
The HTTP Connector:https://tomcat.apache.org/tom...
Customizing ConfigurableServletWebServerFactory Directly:https://docs.spring.io/spring...
推薦閱讀:
《深入理解 Java 內(nèi)存模型》讀書筆記
面試-基礎(chǔ)篇
Spring Boot 2.0 遷移指南
SpringBoot使用Docker快速部署項(xiàng)目
為什么選擇 Spring 作為 Java 框架?
SpringBoot RocketMQ 整合使用和監(jiān)控
Spring Boot 面試的十個(gè)問(wèn)題
上篇好文:
使用 Spring Framework 時(shí)常犯的十大錯(cuò)誤
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75912.html
摘要:需要注意的是必須要使用版本為以上才支持屬性。與格式文件不同,正對(duì)不同的,無(wú)法在一個(gè)文件設(shè)置,官方采用命名形式為格式來(lái)達(dá)成一樣的效果。采用方式添加的是屬于額外激活的,也就是說(shuō)覆蓋掉外部傳入的指定的。 showImg(https://segmentfault.com/img/remote/1460000019924197?w=1050&h=500); Spring Boot Profile...
摘要:探究系統(tǒng)登錄驗(yàn)證碼的實(shí)現(xiàn)后端掘金驗(yàn)證碼生成類手把手教程后端博客系統(tǒng)第一章掘金轉(zhuǎn)眼間時(shí)間就從月份到現(xiàn)在的十一月份了。提供了與標(biāo)準(zhǔn)不同的工作方式我的后端書架后端掘金我的后端書架月前本書架主要針對(duì)后端開(kāi)發(fā)與架構(gòu)。 Spring Boot干貨系列總綱 | 掘金技術(shù)征文 - 掘金原本地址:Spring Boot干貨系列總綱博客地址:http://tengj.top/ 前言 博主16年認(rèn)識(shí)Spin...
摘要:在創(chuàng)建之前,實(shí)際上觸發(fā)了一些事件,因此不能將偵聽(tīng)器注冊(cè)為。使用的事件發(fā)布機(jī)制發(fā)送應(yīng)用程序事件,該機(jī)制的一部分確保在子環(huán)境中發(fā)布給偵聽(tīng)器的事件也會(huì)在任何祖先上下文中被發(fā)布給監(jiān)聽(tīng)器。 23. SpringApplication SpringApplication類提供了一種方便的方法來(lái)引導(dǎo)從main()方法開(kāi)始的Spring應(yīng)用程序。在許多情況下,你可以委托給靜態(tài)SpringApplica...
摘要:有了配置文件之后,啟動(dòng)程序,我們首先可以看到日志輸入,由此可以看出程序讀取了的配置。首先,根據(jù)的全局查找功能,直接搜索這些詞出現(xiàn)的位置,進(jìn)行定位,可以找到這個(gè)日志出現(xiàn)于方法之中。由于我們的配置文件在下,所以只要留意當(dāng)為的程序執(zhí)行情況即可。 前言 上文《一文掌握 Spring Boot Profiles》 是對(duì) Spring Boot Profiles 的介紹和使用,因此本文將從源碼角度...
摘要:滿足這些約束條件和原則的應(yīng)用程序或設(shè)計(jì)就是。需要注意的是,是設(shè)計(jì)風(fēng)格而不是標(biāo)準(zhǔn)。同一個(gè)路徑,因?yàn)檎?qǐng)求方式的不同,而去找尋不同的接口,完成對(duì)資源狀態(tài)的轉(zhuǎn)變。一個(gè)符合風(fēng)格的就可以稱之一個(gè)的接口。 RESTful 相信在座的各位對(duì)于RESTful都是略有耳聞,那么RESTful到底是什么呢? REST(Representational State Transfer)表述性狀態(tài)轉(zhuǎn)移是一組架構(gòu)約...
閱讀 2357·2023-04-25 14:22
閱讀 3773·2021-11-15 18:12
閱讀 1326·2019-08-30 15:44
閱讀 3244·2019-08-29 15:37
閱讀 762·2019-08-29 13:49
閱讀 3490·2019-08-26 12:11
閱讀 917·2019-08-23 18:28
閱讀 1620·2019-08-23 14:55