SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的多種方式
優(yōu)雅停機(jī)在微服務(wù)架構(gòu)中的角色
想象一下,你在一家餐廳用餐,突然服務(wù)員走過(guò)來(lái)說(shuō):“很抱歉,我得下班了,請(qǐng)您盡快結(jié)賬離開(kāi)。”你可能剛剛點(diǎn)了主菜,或許正在等著甜點(diǎn),結(jié)果這個(gè)突如其來(lái)的通知讓你感到非常不滿。你的就餐體驗(yàn)被打斷了,甚至你的賬單也可能出現(xiàn)混亂。與此同時(shí),餐廳的運(yùn)營(yíng)也可能因此變得不順暢,服務(wù)員離開(kāi)后,未完成的訂單和客戶的需求都可能無(wú)法及時(shí)得到處理,產(chǎn)生了不必要的麻煩。
在微服務(wù)架構(gòu)中,這種情況的對(duì)應(yīng)場(chǎng)景是應(yīng)用程序的突發(fā)關(guān)閉。假設(shè)一個(gè)用戶正在發(fā)起一個(gè)請(qǐng)求,這個(gè)請(qǐng)求正在進(jìn)行中時(shí),某個(gè)微服務(wù)卻突然被強(qiáng)制關(guān)閉,或者在維護(hù)過(guò)程中突然停止。這就會(huì)導(dǎo)致用戶的操作被中斷,未處理的請(qǐng)求可能丟失,甚至產(chǎn)生數(shù)據(jù)不一致或錯(cuò)誤的狀態(tài)。
這種場(chǎng)景不僅會(huì)讓用戶體驗(yàn)變差,還可能給后端系統(tǒng)帶來(lái)極大的問(wèn)題。例如,用戶信息可能未能成功保存到數(shù)據(jù)庫(kù)中,或者訂單狀態(tài)沒(méi)有被正確更新,最終造成數(shù)據(jù)的“臟”或不一致。為了避免這種問(wèn)題,優(yōu)雅停機(jī)機(jī)制在現(xiàn)代微服務(wù)系統(tǒng)中變得至關(guān)重要。它確保在服務(wù)關(guān)閉時(shí),所有進(jìn)行中的請(qǐng)求能夠得到適當(dāng)?shù)奶幚?,相關(guān)資源得以順利釋放,避免因應(yīng)用程序的突然關(guān)閉而導(dǎo)致的問(wèn)題。
1、什么是優(yōu)雅停機(jī)
簡(jiǎn)單來(lái)說(shuō),優(yōu)雅停機(jī)就是指當(dāng)我們需要關(guān)閉一個(gè)服務(wù)時(shí),服務(wù)能夠有序地完成當(dāng)前的工作并停止。 具體來(lái)說(shuō),優(yōu)雅停機(jī)包括以下幾個(gè)步驟:
- 停止接收新請(qǐng)求:當(dāng)系統(tǒng)開(kāi)始關(guān)閉時(shí),需要通知負(fù)載均衡器或網(wǎng)關(guān),告知它不要再將新的請(qǐng)求發(fā)送到即將下線的實(shí)例。
- 處理正在進(jìn)行的請(qǐng)求:對(duì)于已經(jīng)到達(dá)并正在處理的請(qǐng)求,系統(tǒng)要給它們完成的機(jī)會(huì),不會(huì)突然中斷。
- 釋放資源:像數(shù)據(jù)庫(kù)連接池、線程池等資源需要被安全釋放,避免資源泄露。
- 持久化臨時(shí)數(shù)據(jù):如果有必要,系統(tǒng)會(huì)保存當(dāng)前的狀態(tài)到數(shù)據(jù)庫(kù)或文件,以便下次啟動(dòng)時(shí)可以恢復(fù)。
2、為什么需要優(yōu)雅停機(jī)
- 部署新版本時(shí)平穩(wěn)過(guò)渡:當(dāng)我們需要更新應(yīng)用時(shí),優(yōu)雅停機(jī)可以讓舊版本服務(wù)平穩(wěn)關(guān)閉,避免突然的停機(jī)對(duì)用戶造成影響。
- 避免資源泄露:不管是內(nèi)存、數(shù)據(jù)庫(kù)連接,還是線程池資源,都需要在關(guān)閉時(shí)釋放,否則就可能導(dǎo)致內(nèi)存泄漏等問(wèn)題。
- 確保數(shù)據(jù)一致性:如果有正在處理的事務(wù),優(yōu)雅停機(jī)可以讓這些事務(wù)有機(jī)會(huì)完成,避免數(shù)據(jù)丟失或者不一致。
3、優(yōu)雅停機(jī)的實(shí)際應(yīng)用場(chǎng)景
服務(wù)更新: 在系統(tǒng)版本升級(jí)時(shí),通過(guò)優(yōu)雅停機(jī)完成請(qǐng)求處理和資源釋放,避免對(duì)用戶造成干擾。
流量調(diào)控: 在高并發(fā)場(chǎng)景下,如果需要暫時(shí)下線部分服務(wù)節(jié)點(diǎn),優(yōu)雅停機(jī)可以幫助實(shí)現(xiàn)“無(wú)感”遷移。
訂單處理: 如出租車平臺(tái),在訂單完成后再下線服務(wù),避免出現(xiàn)
“中途被拋棄”
的情況。
4、優(yōu)雅停機(jī)可能失效的情況
- 強(qiáng)制關(guān)閉:使用
kill -9
強(qiáng)制終止進(jìn)程將導(dǎo)致優(yōu)雅停機(jī)機(jī)制無(wú)法觸發(fā)。 - 資源耗盡:系統(tǒng)資源不足可能導(dǎo)致清理操作無(wú)法完成。
- 未配置超時(shí):如果未配置超時(shí)時(shí)間,處理長(zhǎng)時(shí)間任務(wù)可能導(dǎo)致停機(jī)時(shí)間過(guò)長(zhǎng)。
5、如何在 Spring Boot 中實(shí)現(xiàn)優(yōu)雅停機(jī)
Spring Boot 優(yōu)雅停機(jī)的基礎(chǔ)實(shí)現(xiàn)
- 從
Spring Boot 2.3
開(kāi)始,優(yōu)雅停機(jī)的支持更加簡(jiǎn)單和強(qiáng)大。通過(guò)設(shè)置server.shutdown
配置,可以決定應(yīng)用停機(jī)時(shí)的行為。
立即停機(jī)模式
- 在立即停機(jī)模式下,應(yīng)用會(huì)立刻中斷所有請(qǐng)求和任務(wù)。
server: shutdown: immediate
雖然簡(jiǎn)單高效,但這種方式通常只適用于測(cè)試或無(wú)狀態(tài)服務(wù)。
優(yōu)雅停機(jī)模式
- 在優(yōu)雅停機(jī)模式下,
Spring Boot
會(huì)等待當(dāng)前的處理任務(wù)完成,再進(jìn)行停機(jī)操作。
server: shutdown: graceful
注意: 該模式下的默認(rèn)等待時(shí)間為 30 秒,可通過(guò)
spring.lifecycle.timeout-per-shutdown-phase
進(jìn)行配置。
添加 spring-boot-starter-actuator 依賴
首先,需要確保你的項(xiàng)目中包含了 spring-boot-starter-actuator
依賴,這是啟用 Spring Boot
內(nèi)置監(jiān)控和管理端點(diǎn)的工具包。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
啟用 shutdown 端點(diǎn)
默認(rèn)情況下,Spring Boot
的 shutdown
端點(diǎn)是禁用的。我們需要在 application.properties
或 application.yml
中顯式啟用它。
對(duì)于 application.properties
:
management.endpoint.shutdown.enabled=true management.endpoints.web.exposure.include=shutdown
或者,如果你使用 application.yml
:
management: endpoint: shutdown: enabled: true endpoints: web: exposure: include: "shutdown"
觸發(fā)優(yōu)雅停機(jī)
配置好后,你可以通過(guò)發(fā)送 HTTP
請(qǐng)求來(lái)觸發(fā)優(yōu)雅停機(jī)。例如,使用 curl
命令:
curl -X POST http://localhost:8080/actuator/shutdown
當(dāng)你調(diào)用這個(gè)端點(diǎn)時(shí),Spring Boot
應(yīng)用會(huì)停止接收新的請(qǐng)求,繼續(xù)處理已經(jīng)收到的請(qǐng)求,直到所有請(qǐng)求處理完畢后,應(yīng)用才會(huì)退出。
6、通過(guò) ApplicationListener 接口實(shí)現(xiàn)清理邏輯
為了在應(yīng)用關(guān)閉時(shí)執(zhí)行特定的清理操作(例如關(guān)閉數(shù)據(jù)庫(kù)連接、釋放資源等),你可以實(shí)現(xiàn) ApplicationListener<ContextClosedEvent>
接口。
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.stereotype.Component; @Component public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> { @Override public void onApplicationEvent(ContextClosedEvent event) { // 執(zhí)行必要的清理操作 System.out.println("Starting graceful shutdown..."); try { Thread.sleep(5000); // 模擬清理任務(wù) } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Graceful shutdown completed."); } }
在這個(gè)例子中,我們模擬了一個(gè)清理操作的過(guò)程(通過(guò) Thread.sleep()
來(lái)等待)。實(shí)際上,你可以替換這部分邏輯,比如關(guān)閉數(shù)據(jù)庫(kù)連接、釋放文件句柄等。
7、使用 JVM 的鉤子函數(shù)
Java 提供了 Runtime.addShutdownHook()
方法,可以注冊(cè)一個(gè)線程,在 JVM 終止時(shí)執(zhí)行清理任務(wù)。這個(gè)方法適用于一些更底層的清理操作,尤其是在某些情況下,ApplicationListener
可能沒(méi)有機(jī)會(huì)被觸發(fā)時(shí)。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MainApp { public static void main(String[] args) { // 注冊(cè)關(guān)閉鉤子 Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("JVM is shutting down, executing cleanup..."); try { Thread.sleep(5000); // 模擬清理任務(wù) } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Cleanup completed."); })); SpringApplication.run(MainApp.class, args); } }
需要注意的是,JVM
關(guān)閉鉤子并不總是能執(zhí)行,尤其是在遇到強(qiáng)制停止(如 kill -9
)時(shí)。因此,它應(yīng)該作為一種補(bǔ)充機(jī)制,而不是唯一的保證。
8、觸發(fā)優(yōu)雅停機(jī)的方式
除了通過(guò) /actuator/shutdown
端點(diǎn)來(lái)觸發(fā)優(yōu)雅停機(jī)外,還有一些常見(jiàn)的方法:
SIGTERM 信號(hào):通過(guò)發(fā)送
SIGTERM
信號(hào)(例如使用kill
命令)可以觸發(fā)JVM
的正常退出流程。
kill <pid>
這里的 <pid>
是應(yīng)用的進(jìn)程 ID。
kill -9 pid
可以模擬了一次系統(tǒng)宕機(jī),系統(tǒng)斷電等極端情況,而kill -15 pid
則是等待應(yīng)用關(guān)閉,執(zhí)行阻塞操作,有時(shí)候也會(huì)出現(xiàn)無(wú)法關(guān)閉應(yīng)用的情況
#查看jvm進(jìn)程pid jps #列出所有信號(hào)名稱 kill -l # Windows下信號(hào)常量值 # 簡(jiǎn)稱 全稱 數(shù)值 # INT SIGINT 2 Ctrl+C中斷 # ILL SIGILL 4 非法指令 # FPE SIGFPE 8 floating point exception(浮點(diǎn)異常) # SEGV SIGSEGV 11 segment violation(段錯(cuò)誤) # TERM SIGTERM 5 Software termination signal from kill(Kill發(fā)出的軟件終止) # BREAK SIGBREAK 21 Ctrl-Break sequence(Ctrl+Break中斷) # ABRT SIGABRT 22 abnormal termination triggered by abort call(Abort) #linux信號(hào)常量值 # 簡(jiǎn)稱 全稱 數(shù)值 # HUP SIGHUP 1 終端斷線 # INT SIGINT 2 中斷(同 Ctrl + C) # QUIT SIGQUIT 3 退出(同 Ctrl + \) # KILL SIGKILL 9 強(qiáng)制終止 # TERM SIGTERM 15 終止 # CONT SIGCONT 18 繼續(xù)(與STOP相反, fg/bg命令) # STOP SIGSTOP 19 暫停(同 Ctrl + Z) #.... #可以理解為操作系統(tǒng)從內(nèi)核級(jí)別強(qiáng)行殺死某個(gè)進(jìn)程 kill -9 pid #理解為發(fā)送一個(gè)通知,等待應(yīng)用主動(dòng)關(guān)閉 kill -15 pid #也支持信號(hào)常量值全稱或簡(jiǎn)寫(就是去掉SIG后) kill -l KILL
JVM 工具:Java 提供了一些工具(如 jcmd
和 jconsole
)可以用來(lái)控制 JVM 的生命周期。例如,使用 jcmd
來(lái)發(fā)送退出命令:
jcmd <pid> VM.exit
容器平臺(tái):如果你的應(yīng)用運(yùn)行在
Kubernetes
或Docker
等容器平臺(tái)上,平臺(tái)通常會(huì)在刪除容器時(shí)發(fā)送SIGTERM
信號(hào),并等待一段時(shí)間讓應(yīng)用完成工作。
其他方法
在 Spring Boot 中實(shí)現(xiàn)優(yōu)雅停機(jī)(Graceful Shutdown)除了通過(guò) spring-boot-actuator
、ApplicationListener<ContextClosedEvent>
和 JVM 鉤子
等方式外,實(shí)際上還有一些其他方法可以幫助我們實(shí)現(xiàn)優(yōu)雅停機(jī)。以下是幾種不同的實(shí)現(xiàn)方式,并配合實(shí)際應(yīng)用場(chǎng)景和代碼示例。
1. 使用 @PreDestroy 注解
@PreDestroy
注解是 Java EE
中的一種注解,用來(lái)在 Bean
銷毀之前執(zhí)行清理任務(wù)。Spring
也支持這個(gè)注解,當(dāng) Spring
容器關(guān)閉時(shí),所有帶有 @PreDestroy
注解的方法都會(huì)被調(diào)用。它通常用于執(zhí)行資源的釋放操作,如關(guān)閉數(shù)據(jù)庫(kù)連接池、清理緩存等。
代碼示例:
import javax.annotation.PreDestroy; import org.springframework.stereotype.Component; @Component public class GracefulShutdownService { @PreDestroy public void onShutdown() { System.out.println("Performing cleanup before shutdown..."); // 在此處執(zhí)行資源清理,如關(guān)閉數(shù)據(jù)庫(kù)連接、釋放線程池等 } }
適用場(chǎng)景:
- 適用于需要在應(yīng)用關(guān)閉時(shí)清理資源的場(chǎng)景,尤其是在資源管理方面(例如關(guān)閉連接池、清理緩存等)。
- 在
Web
應(yīng)用中,通常用來(lái)釋放與外部系統(tǒng)(如數(shù)據(jù)庫(kù)、消息隊(duì)列等)的連接。
2. 使用 DisposableBean
接口
Spring 提供了 DisposableBean
接口,用于定義 Bean
在銷毀時(shí)需要執(zhí)行的清理操作。它的 destroy()
方法會(huì)在 Spring
容器關(guān)閉時(shí)被自動(dòng)調(diào)用。
代碼示例:
啟用 Shutdown Hook
Spring Boot
默認(rèn)會(huì)通過(guò) JVM
的 Shutdown Hook 觸發(fā)優(yōu)雅停機(jī)。確保以下配置啟用:
spring: main: register-shutdown-hook: true
自定義資源釋放邏輯
如果需要在停機(jī)時(shí)執(zhí)行特定的清理操作,比如關(guān)閉數(shù)據(jù)庫(kù)連接或停止線程池,可以通過(guò)添加 Shutdown Hook 或?qū)崿F(xiàn) DisposableBean
接口。
import org.springframework.beans.factory.DisposableBean; import org.springframework.stereotype.Component; @Component public class GracefulShutdownService implements DisposableBean { @Override public void destroy() throws Exception { System.out.println("Graceful shutdown - Cleaning up resources..."); // 執(zhí)行清理操作 } }
或者直接通過(guò) JVM 鉤子實(shí)現(xiàn):
Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("執(zhí)行自定義的資源清理邏輯"); }));
超時(shí)機(jī)制
避免因某些請(qǐng)求耗時(shí)過(guò)長(zhǎng)導(dǎo)致系統(tǒng)停機(jī)過(guò)程被阻塞,可以通過(guò)以下配置設(shè)置超時(shí)時(shí)間:
spring: lifecycle: timeout-per-shutdown-phase: 20s # 默認(rèn)30秒
適用場(chǎng)景:
- 與
@PreDestroy
類似,但DisposableBean
提供了一種更明確的方式來(lái)處理Spring
容器中的Bean
銷毀。 - 適用于需要進(jìn)行自定義清理操作(如關(guān)閉連接池、停止后臺(tái)線程等)的場(chǎng)景。
3. 配合自定義線程池實(shí)現(xiàn)優(yōu)雅停機(jī)
如果你的應(yīng)用使用了自定義線程池,想確保所有線程在應(yīng)用關(guān)閉時(shí)能夠有序停止,可以通過(guò)設(shè)置線程池的 shutdown
或 shutdownNow
方法來(lái)實(shí)現(xiàn)。
Spring Boot 提供了多種方式來(lái)創(chuàng)建和配置線程池,如 TaskExecutor
、@Async
等。如果應(yīng)用在停止時(shí)需要等待線程池中的任務(wù)完成,可以通過(guò)以下方式進(jìn)行配置。
代碼示例:
import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; @Component public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> { private final ThreadPoolTaskExecutor taskExecutor; public GracefulShutdownListener(ThreadPoolTaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } @Override public void onApplicationEvent(ContextClosedEvent event) { System.out.println("Shutting down thread pool..."); // 給當(dāng)前線程池中的任務(wù)一些時(shí)間來(lái)完成 taskExecutor.shutdown(); try { // 等待任務(wù)完成 if (!taskExecutor.getThreadPoolExecutor().awaitTermination(60, TimeUnit.SECONDS)) { System.out.println("Timeout reached, forcing shutdown..."); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
適用場(chǎng)景:
- 適用于你的應(yīng)用需要執(zhí)行異步任務(wù)時(shí),并希望確保這些任務(wù)能夠有序地完成,防止強(qiáng)制中斷。
- 適用于后臺(tái)線程池或異步任務(wù)系統(tǒng),確保應(yīng)用關(guān)閉時(shí),任務(wù)能夠平穩(wěn)終止。
4. 在 Kubernetes 中實(shí)現(xiàn)優(yōu)雅停機(jī)
如果你將 Spring Boot
應(yīng)用部署在容器編排平臺(tái)(如 Kubernetes
)上,Kubernetes
會(huì)自動(dòng)幫助你實(shí)現(xiàn)優(yōu)雅停機(jī)。Kubernetes
發(fā)送 SIGTERM
信號(hào),并等待容器停止一定時(shí)間(通常是 30 秒),在這段時(shí)間內(nèi),應(yīng)用應(yīng)當(dāng)完成正在進(jìn)行的請(qǐng)求并清理資源。
你可以通過(guò)設(shè)置 terminationGracePeriodSeconds
來(lái)配置應(yīng)用在收到 SIGTERM
信號(hào)后的最大優(yōu)雅停機(jī)時(shí)間。
配置示例(Kubernetes):
apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 1 template: spec: containers: - name: my-app image: my-app-image ports: - containerPort: 8080 terminationGracePeriodSeconds: 60 # 等待 60 秒
適用場(chǎng)景:
- 當(dāng)應(yīng)用部署在
Kubernetes
或Docker Swarm
等容器平臺(tái)時(shí),這種方式能夠自動(dòng)觸發(fā)優(yōu)雅停機(jī),配合應(yīng)用的優(yōu)雅停機(jī)策略(如通過(guò) Actuator 觸發(fā) shutdown)。 - 適用于容器化部署和云原生應(yīng)用,能夠與平臺(tái)的生命周期管理機(jī)制配合。
5. 使用自定義 shutdown 信號(hào)處理器
如果你不想完全依賴 Spring
提供的機(jī)制,可以實(shí)現(xiàn)一個(gè)自定義的信號(hào)處理器來(lái)捕獲和響應(yīng)關(guān)閉信號(hào)。通過(guò)這種方式,你可以更精細(xì)地控制停機(jī)流程。
代碼示例:
import org.springframework.stereotype.Component; import java.io.IOException; @Component public class ShutdownSignalHandler { public ShutdownSignalHandler() throws IOException { // 注冊(cè) SIGTERM 信號(hào)處理器 Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown)); } private void shutdown() { System.out.println("Received shutdown signal. Performing graceful shutdown..."); // 執(zhí)行清理操作,如關(guān)閉連接池、停止后臺(tái)服務(wù)等 } }
適用場(chǎng)景:
- 如果你需要更靈活的優(yōu)雅停機(jī)控制,可以使用自定義的信號(hào)處理器。
- 適用于需要處理各種不同信號(hào)(如
SIGTERM
、SIGINT
等)的復(fù)雜場(chǎng)景,特別是對(duì)于非 Spring 的基礎(chǔ)設(shè)施組件。
9、小結(jié)
優(yōu)雅停機(jī)是 Spring Boot
應(yīng)用的重要特性,它幫助我們確保在關(guān)閉應(yīng)用時(shí)能夠平穩(wěn)地釋放資源,處理完正在進(jìn)行的請(qǐng)求,從而提高系統(tǒng)的穩(wěn)定性和可靠性。通過(guò) Spring Boot Actuator、ApplicationListener
接口和 JVM 鉤子函數(shù)等多種方式,我們可以確保應(yīng)用程序能夠安全、順利地關(guān)閉,而不會(huì)影響用戶體驗(yàn)或?qū)е聰?shù)據(jù)丟失。
除了 Spring Boot Actuator 和 ApplicationListener
外,還有多種方式可以實(shí)現(xiàn)優(yōu)雅停機(jī)。每種方式有不同的適用場(chǎng)景:
@PreDestroy
和DisposableBean
:適用于簡(jiǎn)單的資源釋放和清理操作。- 自定義線程池清理:適用于需要確保線程池任務(wù)完成的場(chǎng)景。
- 容器平臺(tái)的優(yōu)雅停機(jī):適用于容器化應(yīng)用,
Kubernetes
會(huì)自動(dòng)管理服務(wù)的優(yōu)雅停機(jī)。 - 自定義信號(hào)處理:適用于需要更靈活、底層控制的停機(jī)過(guò)程。
根據(jù)應(yīng)用的需求,你可以選擇合適的方式實(shí)現(xiàn)優(yōu)雅停機(jī),從而提高系統(tǒng)的可靠性和用戶體驗(yàn)。
以上就是SpringBoot實(shí)現(xiàn)優(yōu)雅停機(jī)的多種方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot優(yōu)雅停機(jī)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java面試題沖刺第二十六天--實(shí)戰(zhàn)編程2
這篇文章主要為大家分享了最有價(jià)值的三道java實(shí)戰(zhàn)編程的面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下2021-08-08解決Mybatis中foreach嵌套使用if標(biāo)簽對(duì)象取值的問(wèn)題
這篇文章主要介紹了解決Mybatis中foreach嵌套使用if標(biāo)簽對(duì)象取值的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Java如何判斷一個(gè)空對(duì)象的常見(jiàn)方法
在Java中判斷對(duì)象是否為空是一項(xiàng)重要的編程技巧,可以有效防止空指針異常的發(fā)生,下面這篇文章主要給大家介紹了關(guān)于利用Java如何判斷一個(gè)空對(duì)象的相關(guān)資料,需要的朋友可以參考下2024-01-01Mybatis-Plus根據(jù)自定義注解實(shí)現(xiàn)自動(dòng)加解密的示例代碼
我們把數(shù)據(jù)存到數(shù)據(jù)庫(kù)的時(shí)候,有些敏感字段是需要加密的,從數(shù)據(jù)庫(kù)查出來(lái)再進(jìn)行解密,如果我們使用的是Mybatis框架,那就跟著一起探索下如何使用框架的攔截器功能實(shí)現(xiàn)自動(dòng)加解密吧,需要的朋友可以參考下2024-06-06解決springboot項(xiàng)目找不到resources目錄下的資源問(wèn)題
這篇文章主要介紹了解決springboot項(xiàng)目找不到resources目錄下的資源問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08idea使用帶provide修飾依賴導(dǎo)致ClassNotFound
程序打包到Linux上運(yùn)行時(shí),若Linux上也有這些依賴,為了在Linux上運(yùn)行時(shí)避免依賴沖突,可以使用provide修飾,本文主要介紹了idea使用帶provide修飾依賴導(dǎo)致ClassNotFound,下面就來(lái)介紹一下解決方法,感興趣的可以了解一下2024-01-01Java實(shí)現(xiàn)PDF轉(zhuǎn)Word的示例代碼(無(wú)水印無(wú)頁(yè)數(shù)限制)
這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)PDF轉(zhuǎn)Word文件的效果,并可以無(wú)水印、無(wú)頁(yè)數(shù)限制。文中的示例代碼講解詳細(xì),需要的可以參考一下2022-05-05下載遠(yuǎn)程maven倉(cāng)庫(kù)的jar?手動(dòng)放到本地倉(cāng)庫(kù)詳細(xì)操作
這篇文章主要介紹了如何下載遠(yuǎn)程maven倉(cāng)庫(kù)的jar?手動(dòng)放到本地倉(cāng)庫(kù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03