摘要:在項(xiàng)目中,為滿足以上要求,我們將大量的參數(shù)配置在或文件中,通過注解,我們可以方便的獲取這些參數(shù)值使用配置模塊假設(shè)我們正在搭建一個(gè)發(fā)送郵件的模塊。這使得在不影響其他模塊的情況下重構(gòu)一個(gè)模塊中的屬性變得容易。
在編寫項(xiàng)目代碼時(shí),我們要求更靈活的配置,更好的模塊化整合。在 Spring Boot 項(xiàng)目中,為滿足以上要求,我們將大量的參數(shù)配置在 application.properties 或 application.yml 文件中,通過 @ConfigurationProperties 注解,我們可以方便的獲取這些參數(shù)值
使用 @ConfigurationProperties 配置模塊假設(shè)我們正在搭建一個(gè)發(fā)送郵件的模塊。在本地測(cè)試,我們不想該模塊真的發(fā)送郵件,所以我們需要一個(gè)參數(shù)來「開關(guān)」 disable 這個(gè)功能。另外,我們希望為這些郵件配置一個(gè)默認(rèn)的主題,這樣,當(dāng)我們查看郵件收件箱,通過郵件主題可以快速判斷出這是測(cè)試郵件
在 application.properties 文件中創(chuàng)建這些參數(shù):
我們可以使用 @Value 注解或著使用 Spring Environment bean 訪問這些屬性,是這種注入配置方式有時(shí)顯得很笨重。我們將使用更安全的方式(@ConfigurationProperties )來獲取這些屬性
@ConfigurationProperties 的基本用法非常簡單:我們?yōu)槊總€(gè)要捕獲的外部屬性提供一個(gè)帶有字段的類。請(qǐng)注意以下幾點(diǎn):
前綴定義了哪些外部屬性將綁定到類的字段上
根據(jù) Spring Boot 寬松的綁定規(guī)則,類的屬性名稱必須與外部屬性的名稱匹配
我們可以簡單地用一個(gè)值初始化一個(gè)字段來定義一個(gè)默認(rèn)值
類本身可以是包私有的
類的字段必須有公共 setter 方法
Spring 寬松綁定規(guī)則 (relaxed binding)Spring使用一些寬松的綁定屬性規(guī)則。因此,以下變體都將綁定到 hostName 屬性上:
如果我們將 MailModuleProperties 類型的 bean 注入到另一個(gè) bean 中,這個(gè) bean 現(xiàn)在可以以類型安全的方式訪問那些外部配置參數(shù)的值。
但是,我們?nèi)匀恍枰?Spring 知道我們的 @ConfigurationProperties 類存在,以便將其加載到應(yīng)用程序上下文中( 面試還不知道 BeanFactory 和 ApplicationContext 的區(qū)別?)
激活 @ConfigurationProperties對(duì)于 Spring Boot,創(chuàng)建一個(gè) MailModuleProperties 類型的 bean,我們可以通過下面幾種方式將其添加到應(yīng)用上下文中
首先,我們可以通過添加 @Component 注解讓 Component Scan 掃描到
很顯然,只有當(dāng)類所在的包被 Spring @ComponentScan 注解掃描到才會(huì)生效,默認(rèn)情況下,該注解會(huì)掃描在主應(yīng)用類下的所有包結(jié)構(gòu)
我們也可以通過 Spring 的 Java Configuration 特性實(shí)現(xiàn)同樣的效果:
只要 MailModuleConfiguration 類被 Spring Boot 應(yīng)用掃描到,我們就可以在應(yīng)用上下文中訪問 MailModuleProperties bean
我們還可以使用 @EnableConfigurationProperties 注解讓我們的類被 Spring Boot 所知道,在該注解中其實(shí)是用了@Import(EnableConfigurationPropertiesImportSelector.class) 實(shí)現(xiàn),大家可以看一下
激活一個(gè) @ConfigurationProperties 類的最佳方式是什么?無法轉(zhuǎn)換的屬性所有上述方法都同樣有效。然而,我建議模塊化你的應(yīng)用程序,并讓每個(gè)模塊提供自己的@ConfigurationProperties 類,只提供它需要的屬性,就像我們?cè)谏厦娴拇a中對(duì)郵件模塊所做的那樣。這使得在不影響其他模塊的情況下重構(gòu)一個(gè)模塊中的屬性變得容易。
因此,我不建議在應(yīng)用程序類本身上使用 @EnableConfigurationProperties,如許多其他教程中所示,是在特定于模塊的 @Configuration 類上使用@EnableConfigurationProperties,該類也可以利用包私有的可見性對(duì)應(yīng)用程序的其余部分隱藏屬性。
如果我們?cè)?application.properties 屬性上定義的屬性不能被正確的解析會(huì)發(fā)生什么?假如我們?yōu)樵緫?yīng)該為布爾值的屬性提供的值為 "foo":
默認(rèn)情況下,Spring Boot 將會(huì)啟動(dòng)失敗,并拋出異常:
Failed to bind properties under "myapp.mail.enabled" to java.lang.Boolean: Property: myapp.mail.enabled Value: foo Origin: class path resource [application.properties]:1:20 Reason: failed to convert java.lang.String to java.lang.Boolean
當(dāng)我們?yōu)閷傩耘渲缅e(cuò)誤的值時(shí),而又不希望 Spring Boot 應(yīng)用啟動(dòng)失敗,我們可以設(shè)置 ignoreInvalidFields 屬性為 true (默認(rèn)為 false)
這樣,Spring Boot 將會(huì)設(shè)置 enabled 字段為我們?cè)?Java 代碼里設(shè)定好的默認(rèn)值。如果我們沒有設(shè)置默認(rèn)值,enabled 將為 null,因?yàn)檫@里定義的是 boolean 的包裝類 Boolean
未知的屬性和上面的情況有些相反,如果我們?cè)?application.properties 文件提供了 MailModuleProperties 類不知道的屬性會(huì)發(fā)生什么?
默認(rèn)情況下,Spring Boot 會(huì)忽略那些不能綁定到 @ConfigurationProperties 類字段的屬性
然而,當(dāng)配置文件中有一個(gè)屬性實(shí)際上沒有綁定到 @ConfigurationProperties 類時(shí),我們可能希望啟動(dòng)失敗。也許我們以前使用過這個(gè)配置屬性,但是它已經(jīng)被刪除了,這種情況我們希望被觸發(fā)告知手動(dòng)從 application.properties 刪除這個(gè)屬性
為了實(shí)現(xiàn)上述情況,我們僅需要將 ignoreUnknownFields 屬性設(shè)置為 false (默認(rèn)是 true)
現(xiàn)在,應(yīng)用啟動(dòng)時(shí),控制臺(tái)會(huì)反饋我們異常信息
Binding to target [Bindable@cf65451 type = com.example.configurationproperties.properties.MailModuleProperties, value = "provided", annotations = array[@org.springframework.boot.context.properties.ConfigurationProperties(value=myapp.mail, prefix=myapp.mail, ignoreInvalidFields=false, ignoreUnknownFields=false)]] failed: Property: myapp.mail.unknown-property Value: foo Origin: class path resource [application.properties]:3:29 Reason: The elements [myapp.mail.unknown-property] were left unbound.
棄用警告??(Deprecation Warning)啟動(dòng)時(shí)校驗(yàn) @ConfigurationProperties
ignoreUnknownFields 在未來 Spring Boot 的版本中會(huì)被標(biāo)記為 deprecated,因?yàn)槲覀兛赡苡袃蓚€(gè)帶有 @ConfigurationProperties 的類,同時(shí)綁定到了同一個(gè)命名空間 (namespace) 上,其中一個(gè)類可能知道某個(gè)屬性,另一個(gè)類卻不知道某個(gè)屬性,這樣就會(huì)導(dǎo)致啟動(dòng)失敗
如果我們希望配置參數(shù)在傳入到應(yīng)用中時(shí)有效的,我們可以通過在字段上添加 bean validation 注解,同時(shí)在類上添加 @Validated 注解
如果我們忘記在 application.properties 文件設(shè)置 enabled 屬性,并且設(shè)置 defaultSubject 為空
應(yīng)用啟動(dòng)時(shí),我們將會(huì)得到 BindValidationException
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under "myapp.mail" to com.example.configurationproperties.properties.MailModuleProperties failed: Property: myapp.mail.enabled Value: null Reason: must not be null Property: myapp.mail.defaultSubject Value: null Reason: must not be empty
當(dāng)然這些默認(rèn)的驗(yàn)證注解不能滿足你的驗(yàn)證要求,我們也可以自定義注解
如果你的驗(yàn)證邏輯很特殊,我們可以實(shí)現(xiàn)一個(gè)方法,并用 @PostConstruct 標(biāo)記,如果驗(yàn)證失敗,方法拋出異常即可, 關(guān)于 @PostConstruct,可以查看 Spring Bean 的生命周期,我從哪里來?
復(fù)雜屬性類型多數(shù)情況,我們傳遞給應(yīng)用的參數(shù)是基本的字符串或數(shù)字。但是,有時(shí)我們需要傳遞諸如 List 的數(shù)據(jù)類型
List 和 Set假如,我們?yōu)猷]件模塊提供了一個(gè) SMTP 服務(wù)的列表,我們可以添加該屬性到 MailModuleProperties 類中
我們有兩種方式讓 Spring Boot 自動(dòng)填充該 list 屬性
application.properties在 application.properties 文件中以數(shù)組形式書寫
YAML 本身支持 list 類型,所以可以在 application.yml 文件中添加:
set 集合也是這種方式的配置方式,不再重復(fù)書寫。另外YAML 是更好的閱讀方式,層次分明,所以在實(shí)際應(yīng)用中更推薦大家使用該種方式做數(shù)據(jù)配置
DurationSpring Boot 內(nèi)置支持從配置參數(shù)中解析 durations (持續(xù)時(shí)間),官網(wǎng)文檔 給出了明確的說明
我們既可以配置毫秒數(shù)數(shù)值,也可配置帶有單位的文本:
官網(wǎng)上已明確說明,配置 duration 不寫單位,默認(rèn)按照毫秒來指定,我們也可已通過 @DurationUnit 來指定單位:
常用單位如下:
ns for nanoseconds (納秒)
us for microseconds (微秒)
ms for milliseconds (毫秒)
s for seconds (秒)
m for minutes (分)
h for hours (時(shí))
d for days (天)
DataSize與 Duration 的用法一毛一樣,默認(rèn)單位是 byte (字節(jié)),可以通過 @DataSizeUnit 單位指定:
添加配置
但是,我測(cè)試的時(shí)候打印出來結(jié)果都是以 B (bytes) 來顯示
常見單位如下:
B for bytes
KB for kilobytes
MB for megabytes
GB for gigabytes
TB for terabytes
自定義類型有些情況,我們想解析配置參數(shù)到我們自定義的對(duì)象類型上,假設(shè),我們我們?cè)O(shè)置最大包裹重量:
在 MailModuleProperties 中添加 Weight 屬性
我們可以模仿 DataSize 和 Duration 創(chuàng)造自己的 converter (轉(zhuǎn)換器)
將其注冊(cè)到 Spring Boot 上下文中
@ConfigurationPropertiesBinding 注解是讓 Spring Boot 知道使用該轉(zhuǎn)換器做數(shù)據(jù)綁定
使用 Spring Boot Configuration Processor 完成自動(dòng)補(bǔ)全我們向項(xiàng)目中添加依賴:
Maven Gradle重新 build 項(xiàng)目之后,configuration processor 會(huì)為我們創(chuàng)建一個(gè) JSON 文件:
這樣,當(dāng)我們?cè)?application.properties 和 application.yml 中寫配置的時(shí)候會(huì)有自動(dòng)提醒:
configuration processor 允許我們標(biāo)記某一個(gè)屬性為 deprecated
我們可以通過添加 @DeprecatedConfigurationProperty 注解到字段的 getter 方法上,來標(biāo)示該字段為 deprecated,重新 build 項(xiàng)目,看看 JSON 文件發(fā)生了什么?
當(dāng)我們?cè)倬帉懪渲梦募r(shí),已經(jīng)給出了明確 deprecated 提示:
Spring Boot 的 @ConfigurationProperties 注解在綁定類型安全的 Java Bean 時(shí)是非常強(qiáng)大的,我們可以配合其注解屬性和 @DeprecatedConfigurationProperty 注解獲取到更友好的編程方式,同時(shí)這樣讓我們的配置更加模塊化。
附加說明以為 @ConfigurationProperties 注解滿足我們的全部需要了嗎?其實(shí)不然,Spring 官網(wǎng)明確給出了該注解和 @Value 注解的對(duì)比:
如果使用 SpEL 表達(dá)式,我們只能選擇 @Value 注解
另外我之前在閱讀 RabbitMQ 源碼時(shí),發(fā)現(xiàn) RabbitProperties 類充分的利用了 @ConfigurationProperties 注解特性:
deprecated
Duration
Enum
嵌套屬性
感覺自己后知后覺,最近在思考,為什么小時(shí)候要閱讀和背誦古詩詞,文言文等經(jīng)典,因?yàn)檫@樣寫文章就可以輕松熟練的引用經(jīng)典。技術(shù)也一樣,各種框架的源碼就是學(xué)生時(shí)代的古詩詞和文言文,我們要多多查看閱讀,甚至背誦編程思想,這樣就可以寫出越來越優(yōu)雅的代碼
關(guān)于 @ConfigurationProperties 注解的使用,這里推薦 RabbitMQ Github 源碼,只需看這一個(gè)類就可以,知道怎樣充分利用這個(gè)注解.
Demo 代碼獲取,回復(fù)公眾號(hào)「demo」,打開鏈接查看對(duì)應(yīng)的子文件夾即可
靈魂追問在實(shí)際項(xiàng)目中, 你能夠充分利用這些特性讓你的配置更靈活和模塊化嗎?
閱讀框架源碼時(shí),他們都是怎樣配置的呢?
@Value 注解怎樣給出默認(rèn)值?
提高效率工具[center]
推薦閱讀紅黑樹,超強(qiáng)動(dòng)靜圖詳解,簡單易懂
只會(huì)用 git pull ?有時(shí)候你可以嘗試更優(yōu)雅的處理方式
雙親委派模型:大廠高頻面試題,輕松搞定
面試還不知道BeanFactory和ApplicationContext的區(qū)別?
如何設(shè)計(jì)好的RESTful API
歡迎持續(xù)關(guān)注公眾號(hào):「日拱一兵」前沿 Java 技術(shù)干貨分享
高效工具匯總
面試問題分析與解答
技術(shù)資料領(lǐng)取
以讀偵探小說思維輕松趣味學(xué)習(xí) Java 技術(shù)棧相關(guān)知識(shí),本著將復(fù)雜問題簡單化,抽象問題具體化和圖形化原則逐步分解技術(shù)問題,技術(shù)持續(xù)更新,請(qǐng)持續(xù)關(guān)注......
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77914.html
摘要:在項(xiàng)目中,為滿足以上要求,我們將大量的參數(shù)配置在或文件中,通過注解,我們可以方便的獲取這些參數(shù)值使用配置模塊假設(shè)我們正在搭建一個(gè)發(fā)送郵件的模塊。這使得在不影響其他模塊的情況下重構(gòu)一個(gè)模塊中的屬性變得容易。 在編寫項(xiàng)目代碼時(shí),我們要求更靈活的配置,更好的模塊化整合。在 Spring Boot 項(xiàng)目中,為滿足以上要求,我們將大量的參數(shù)配置在 application.properties 或...
摘要:也是自帶的一個(gè)基于線程池設(shè)計(jì)的定時(shí)任務(wù)類。其每個(gè)調(diào)度任務(wù)都會(huì)分配到線程池中的一個(gè)線程執(zhí)行,所以其任務(wù)是并發(fā)執(zhí)行的,互不影響。 原創(chuàng)不易,如需轉(zhuǎn)載,請(qǐng)注明出處https://www.cnblogs.com/baixianlong/p/10659045.html,否則將追究法律責(zé)任?。?! 一、在JAVA開發(fā)領(lǐng)域,目前可以通過以下幾種方式進(jìn)行定時(shí)任務(wù) 1、單機(jī)部署模式 Timer:jdk中...
摘要:豐富的特性還支持通知過期等等特性。到這個(gè)就說明測(cè)試通過了。主要針對(duì)方法配置,能夠根據(jù)方法的請(qǐng)求參數(shù)對(duì)其進(jìn)行緩存,常用于查詢操作主要針對(duì)方法配置,能夠根據(jù)方法的請(qǐng)求參數(shù)對(duì)其進(jìn)行緩存,常用于修改操作清空緩存,主要用于刪除操作。 [TOC] Redis簡介 Redis 是一個(gè)開源的使用 ANSI C 語言編寫、遵守 BSD 協(xié)議、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value 數(shù)...
摘要:動(dòng)態(tài)地代理,可以猜測(cè)一下它的含義,在運(yùn)行時(shí)動(dòng)態(tài)地對(duì)某些東西代理,代理它做了其他事情。所以動(dòng)態(tài)代理的內(nèi)容重點(diǎn)就是這個(gè)。所以下一篇我們來細(xì)致了解下的到底是怎么使用動(dòng)態(tài)代理的。 之前講了《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》,本來打算下一篇講講Srping的AOP的,但是其中會(huì)涉及到Java的動(dòng)態(tài)代理,所以先單獨(dú)一篇來了解下Java的動(dòng)態(tài)代理到底是什么,Java是怎么實(shí)現(xiàn)它的。 ...
摘要:前言上一次我們對(duì)的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來聊聊。 showImg(https://segmentfault.com/img/remote/1460000020077803?w=1280&h=853); 前言 上一次我們對(duì)Paging的應(yīng)用進(jìn)行了一次全面的分析,這一次我們來聊聊WorkManager。 如果你對(duì)Paging還未了解,推薦閱讀這篇文章: Paging在Recy...
閱讀 997·2021-11-18 13:23
閱讀 717·2021-11-08 13:16
閱讀 836·2021-10-11 10:58
閱讀 3486·2021-09-22 15:26
閱讀 1713·2021-09-08 10:42
閱讀 1781·2021-09-04 16:45
閱讀 1717·2019-08-30 15:54
閱讀 2547·2019-08-30 13:45