SpringBoot @ConfigurationProperties + Validation實現(xiàn)啟動期校驗解決方案
小明成長記:@ConfigurationProperties+Validation實現(xiàn)啟動期校驗
事故回顧:周三下午 2 點,監(jiān)控系統(tǒng)突然告警,某核心服務(wù)的錯誤日志激增。小明和小伙伴們立刻被拉進(jìn)緊急會議。經(jīng)排查,發(fā)現(xiàn)錯誤原因是:一個新上線的短信推送功能,其服務(wù)商API URL在線上環(huán)境的配置文件中完全缺失。導(dǎo)致RestTemplate在調(diào)用時,注入的String類型的 URL 為null,最終在運(yùn)行時拋出了NullPointerException。
甩鍋現(xiàn)場:
- 部門老大:“這個功能測試環(huán)境不是好好的嗎?為什么線上掛了?誰負(fù)責(zé)的配置?”
- 運(yùn)維同事:“部署流程都是自動化的,配置是根據(jù)開發(fā)提供的清單來管理的。清單里沒寫這個新配置項,我們當(dāng)然不知道要配。”
- 小明(內(nèi)心OS):“完了,這個功能是我做的。我以為大家都會看代碼,知道要配這個……”
老大批示:
“小明,這次的問題根源是配置管理不規(guī)范。你立刻整改代碼,要讓程序在啟動的時候自己告訴我們?nèi)绷耸裁磁渲?,而不是等到用戶用的時候才崩潰! 以后絕不允許再發(fā)生這種低級錯誤!”
小明的任務(wù):
對代碼進(jìn)行改造,利用 @ConfigurationProperties 在應(yīng)用啟動階段對關(guān)鍵參數(shù)進(jìn)行強(qiáng)校驗,避免配置缺失導(dǎo)致運(yùn)行時出錯。
小明的改造方案:使用@ConfigurationProperties進(jìn)行啟動期校驗
小明決定采用 Spring Boot 官方推薦的 @ConfigurationProperties + Validation 方案。這樣,如果配置缺失或不符合規(guī)則,應(yīng)用將根本無法啟動,并在日志中明確打印出缺失的配置項,運(yùn)維同學(xué)直接拿著錯誤信息去補(bǔ)配置即可。
第一步:引入校驗依賴
首先,他檢查了項目的 pom.xml,確保包含了 spring-boot-starter-validation 依賴。這是實現(xiàn)校驗功能的基礎(chǔ)。
<!-- 如果使用的是 Spring Boot 2.3+ 版本,需要顯式引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>第二步:創(chuàng)建配置屬性類并添加校驗規(guī)則
小明為短信服務(wù)創(chuàng)建了一個專門的配置屬性類,將所有相關(guān)的配置項集中管理。
package com.example.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
/**
* 短信服務(wù)配置
* 使用 @Validated 注解開啟校驗
* 使用 @ConfigurationProperties 綁定前綴為 "sms" 的配置
*/
@Component
@Validated // 關(guān)鍵注解1:告訴Spring需要對此Bean進(jìn)行校驗
@ConfigurationProperties(prefix = "sms") // 關(guān)鍵注解2:綁定配置前綴
public class SmsProperties {
/**
* 服務(wù)商API地址
* 本次事故的罪魁禍?zhǔn)祝?
* @NotBlank 確保該值不能為 null 或空字符串
*/
@NotBlank(message = "【短信服務(wù)】關(guān)鍵配置 'sms.url' 未配置,請檢查配置文件!")
private String url;
/**
* 授權(quán)密鑰
*/
@NotBlank(message = "【短信服務(wù)】關(guān)鍵配置 'sms.secret-id' 未配置")
private String secretId;
/**
* 操作密鑰
*/
@NotBlank(message = "【短信服務(wù)】關(guān)鍵配置 'sms.secret-key' 未配置")
private String secretKey;
/**
* 重試次數(shù)
* @NotNull 確保數(shù)字類型的配置不為空
* @Min 設(shè)置最小值
*/
@NotNull(message = "【短信服務(wù)】配置 'sms.retry-times' 未配置")
@Min(value = 0, message = "【短信服務(wù)】配置 'sms.retry-times' 的值不能小于0")
private Integer retryTimes;
/**
* 是否啟用短信服務(wù)(生產(chǎn)環(huán)境才啟用,開發(fā)測試環(huán)境可能不啟用)
* 這里使用了默認(rèn)值 false,即使不配置也不會報錯
*/
private Boolean enabled = false;
// 標(biāo)準(zhǔn)的 Getter 和 Setter 方法必須存在,否則配置無法注入
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSecretId() {
return secretId;
}
public void setSecretId(String secretId) {
this.secretId = secretId;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public Integer getRetryTimes() {
return retryTimes;
}
public void setRetryTimes(Integer retryTimes) {
this.retryTimes = retryTimes;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
}第三步:在業(yè)務(wù)代碼中注入使用
改造原來的代碼,不再直接使用 @Value 注入單個屬性,而是注入這個完整的配置 Bean。
package com.example.demo.service;
import com.example.demo.config.SmsProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SmsService {
// 直接注入配置Bean
private final SmsProperties smsProperties;
@Autowired
public SmsService(SmsProperties smsProperties) {
this.smsProperties = smsProperties;
}
public void sendSms(String phoneNumber, String content) {
// 使用配置
if (Boolean.TRUE.equals(smsProperties.getEnabled())) {
String targetUrl = smsProperties.getUrl(); // 這里拿到的url肯定是有效的
String secretId = smsProperties.getSecretId();
// ... 實際調(diào)用發(fā)送邏輯
System.out.println("正在調(diào)用短信服務(wù): " + targetUrl);
} else {
System.out.println("短信服務(wù)未啟用,已忽略發(fā)送。");
}
}
}第四步:準(zhǔn)備配置文件
錯誤的配置 (application.yml) - 用于復(fù)現(xiàn)事故:
sms: # url: https://api.sms-service.com/send # 故意注釋掉,模擬遺忘配置 secret-id: your_secret_id_here # secret-key: your_secret_key_here # 也注釋掉一個 retry-times: -1 # 配置了一個非法的值
第五步:啟動應(yīng)用,觀察效果
當(dāng)小明啟動應(yīng)用時,應(yīng)用根本無法啟動,控制臺會立即打印出如下非常清晰的錯誤信息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'sms' to com.example.demo.config.SmsProperties failed:
Property: sms.url
Value: null
Reason: 【短信服務(wù)】關(guān)鍵配置 'sms.url' 未配置,請檢查配置文件!
Property: sms.secret-key
Value: null
Reason: 【短信服務(wù)】關(guān)鍵配置 'sms.secret-key' 未配置
Property: sms.retry-times
Value: -1
Reason: 【短信服務(wù)】配置 'sms.retry-times' 的值不能小于0
Action:
Update your application's configuration改造后的成效
- 啟動即發(fā)現(xiàn):配置問題在應(yīng)用啟動之初就被發(fā)現(xiàn),無法形成部署包,根本不會影響線上用戶。
- 責(zé)任清晰:錯誤信息極其明確,直接指出是哪個配置前綴(
sms)下的哪個屬性(url、secret-key)出了問題,以及原因。運(yùn)維同學(xué)無需再問開發(fā),直接看日志就能完成配置。 - 溝通成本降低:開發(fā)人員只需提供配置屬性類的定義(可以作為文檔),運(yùn)維按圖索驥即可。
message屬性中的中文提示更是大大提升了溝通效率。 - 代碼更健壯:配置集中管理,結(jié)構(gòu)清晰,避免了散落的
@Value,易于維護(hù)和擴(kuò)展。
小明將改造后的代碼提交上線后,部門老大對此表示了肯定。從此,團(tuán)隊的配置管理流程變得更加規(guī)范,再也沒有發(fā)生過因配置缺失導(dǎo)致的線上故障。
到此這篇關(guān)于SpringBoot @ConfigurationProperties + Validation實現(xiàn)啟動期校驗解決方案的文章就介紹到這了,更多相關(guān)SpringBoot @ConfigurationProperties Validation啟動校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot使用@ConfigurationProperties實現(xiàn)自動綁定配置參數(shù)屬性
- SpringBoot中的@ConfigurationProperties注解的使用
- SpringBoot中@ConfigurationProperties自動獲取配置參數(shù)的流程步驟
- SpringBoot中@Value獲取值和@ConfigurationProperties獲取值用法及比較
- springboot中@ConfigurationProperties無效果的解決方法
- SpringBoot中@ConfigurationProperties注解的使用與源碼詳解
- SpringBoot利用validation實現(xiàn)數(shù)據(jù)校驗完整指南
- SpringBoot使用spring-boot-starter-validation實現(xiàn)參數(shù)校驗
- SpringBoot利用Validation包實現(xiàn)高效參數(shù)校驗
相關(guān)文章
Java使用JDBC向MySQL數(shù)據(jù)庫批次插入10W條數(shù)據(jù)(測試效率)
使用JDBC連接MySQL數(shù)據(jù)庫進(jìn)行數(shù)據(jù)插入的時候,特別是大批量數(shù)據(jù)連續(xù)插入(100000),如何提高效率呢?今天小編通過本教程給大家介紹下2016-12-12
SpringBoot集成WebSocket實現(xiàn)后臺向前端推送信息的示例
這篇文章主要介紹了SpringBoot集成WebSocket實現(xiàn)后臺向前端推送信息的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
MyBatis如何通過xml方式實現(xiàn)SaveOrUpdate
這篇文章主要講如何通過xml方式實現(xiàn)SaveOrUpdate,但是仍然建議在Service中實現(xiàn),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-06-06
visual studio 2019安裝配置可編寫c/c++語言的IDE環(huán)境
這篇文章主要介紹了visual studio 2019安裝配置可編寫c/c++語言的IDE環(huán)境,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Android studio按鈕點擊頁面跳轉(zhuǎn)詳細(xì)步驟
在Android應(yīng)用程序中,頁面跳轉(zhuǎn)是非常常見的操作,下面這篇文章主要給大家介紹了關(guān)于Android studio按鈕點擊頁面跳轉(zhuǎn)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06

