這個章節(jié)深入挖掘Spring boot的細節(jié),你可以了解到你想使用或定制的關(guān)鍵功能蒲祈。如果你還沒準備好,請先閱讀入門指南和使用Spring Boot章節(jié),以便您有良好的基礎(chǔ)知識漠烧。
4.1 SpringApplication
SpringApplication類提供了一個快捷的方式來引導(dǎo)Spring Boot的啟動,通過main方法靡砌。在許多情況下已脓,您可以委派給靜態(tài)SpringApplication.run方法,如以下示例所示:
public static void main(String[] args) {
SpringApplication.run(MySpringConfiguration.class, args);
}
當你的應(yīng)用啟動時通殃,你會看到和下面相似的輸出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.2.6.RELEASE
2019-04-31 13:09:54.117 INFO 56603 --- [ main] o.s.b.s.app.SampleApplication : Starting SampleApplication v0.1.0 on mycomputer with PID 56603 (/apps/myapp.jar started by pwebb)
2019-04-31 13:09:54.166 INFO 56603 --- [ main] ationConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6e5a8246: startup date [Wed Jul 31 00:08:16 PDT 2013]; root of context hierarchy
2019-04-01 13:09:56.912 INFO 41370 --- [ main] .t.TomcatServletWebServerFactory : Server initialized with port: 8080
2019-04-01 13:09:57.501 INFO 41370 --- [ main] o.s.b.s.app.SampleApplication : Started SampleApplication in 2.992 seconds (JVM running for 3.658)
默認展示一些INFO級別的日志度液,包括一些相關(guān)的啟動細節(jié),例如啟動應(yīng)用的用戶画舌。如果你需要一個不是INFO級別的日志輸出堕担,你可以像在日志級別中描述的一樣設(shè)置它。主應(yīng)用程序類包中使用的實現(xiàn)版本確定應(yīng)用程序版本.啟動日志信息可以通過設(shè)置spring.main.log-startup-info為false來關(guān)閉它骗炉。這還將關(guān)閉對應(yīng)用程序活動配置文件的日志記錄照宝。
要在啟動期間添加其他日志記錄,可以在SpringApplication的子類中重寫logStartupInfo(boolean)句葵。
4.1.1 啟動失敗
如果您的應(yīng)用程序無法啟動厕鹃,則已注冊的FailureAnalyzers將有機會提供專門的錯誤消息和解決該問題的具體措施。 例如乍丈,如果您在端口8080上啟動Web應(yīng)用程序剂碴,并且該端口已在使用中,則應(yīng)該看到類似于以下消息的內(nèi)容:
***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Spring Boot提供匿名的FailureAnalyzers實現(xiàn)轻专,你也可以添加自己的
如果沒有故障分析器能夠處理異常忆矛,您仍然可以顯示完整情況報告以更好地了解出了什么問題。這樣做你需要 org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener開啟debug屬性或者開啟debug日志
舉個例子,如果使用java -jar運行應(yīng)用程序催训,則可以按以下方式啟用debug屬性:
$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug
4.1.2 懶加載
SpringApplication允許應(yīng)用惰性初始化洽议。如果應(yīng)用開啟了懶加載,Bean會在需要時創(chuàng)建而不是應(yīng)用啟動時創(chuàng)建漫拭。這樣亚兄,就可以縮短應(yīng)用啟動花費的時間。在Web應(yīng)用中采驻,懶加載會是需要Web相關(guān)的Bean直到一個HTTP請求到來時才被初始化审胚。
懶加載的一個缺點是會延遲發(fā)現(xiàn)應(yīng)用問題的時間。如果配置錯誤的bean延遲初始化礼旅,則啟動期間將不再發(fā)生故障膳叨,只有在初始化bean時問題才會顯現(xiàn)。還必須注意確保JVM有足夠的內(nèi)存來容納所有應(yīng)用程序的bean痘系,而不僅僅是啟動期間初始化的那些bean菲嘴。由于這些原因,默認情況下不會啟用延遲初始化碎浇,因此建議在啟用延遲初始化之前先對JVM的堆大小進行微調(diào)临谱。
可以使用SpringApplicationBuilder上的lazyInitialization方法或SpringApplication上的setLazyInitialization方法以編程方式啟用延遲初始化,或者奴璃,可以使用spring.main.lazy-initialization屬性啟用它悉默,如以下示例所示:
spring.main.lazy-initialization = true
如果要在對應(yīng)用程序其余部分使用延遲初始化時禁用某些Bean的延遲初始化,則可以使用@Lazy(false)批注將它們的延遲屬性顯式設(shè)置為false苟穆。
4.1.3 定制Banner
可以通過將banner.txt文件添加到類路徑或?qū)pring.banner.location屬性設(shè)置為此類文件的位置來更改啟動時打印的banner抄课。如果該文件使用UTF-8之外的編碼,可以設(shè)置spring.banner.charset屬性雳旅。除了文本文件之外跟磨,您還可以將banner.gif,banner.jpg或banner.png圖像文件添加到類路徑中攒盈,或設(shè)置spring.banner.image.location屬性抵拘。 圖像將轉(zhuǎn)換為ASCII藝術(shù)作品并打印在任何文本橫幅上方。
在banner.txt文件中型豁,你可以設(shè)置下列任何一個占位符:
Table 4 Banner變量
Variable | Desription |
---|---|
${application.version} | 您的應(yīng)用程序的版本號僵蛛,在MANIFEST.MF中聲明,例如迎变,實現(xiàn)版本:1.0被打印為1.0充尉。 |
${application.formatted-version} | 您在MANIFEST.MF中聲明的應(yīng)用程序的版本號,其格式用于顯示(用方括號括起來并以v開頭)衣形, 例如(v1.0) |
${spring-boot.version} | 您正在使用的Spring Boot版本驼侠。 例如2.2.6.RELEASE |
${spring-boot.formatted-version} | 您正在使用的Spring Boot版本,其格式用于顯示(用方括號括起來并以v開頭), 例如(v2.2.6.RELEASE) |
${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME}) | 其中NAME是ANSI轉(zhuǎn)義代碼的名稱倒源, 有關(guān)詳細信息苛预,請參見AnsiPropertySource |
${application.title} | 您在MANIFEST.MF中聲明的應(yīng)用程序的標題。 例如相速,“實現(xiàn)標題”:MyApp被打印為MyApp |
如果要以編程方式生成banner碟渺,可以使用SpringApplication.setBanner()方法鲜锚。 使用org.springframework.boot.Banner接口并實現(xiàn)自己的printBanner()方法突诬。
您還可以使用spring.main.banner-mode屬性來確定橫幅是否必須在System.out(控制臺)上打印,是否必須發(fā)送到配置的記錄器(日志)或根本不打游叻薄(關(guān)閉)旺隙。
打印的橫幅廣告使用以下名稱注冊為單例bean:springBootBanner。
4.1.4 定制SpringApplication
如果默認的SpringApplication不符合您的要求骏令,您可以生成一個本地實例并定制它作為替代蔬捷,例如,關(guān)閉打印banner榔袋,你可以這樣寫:
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
傳遞給SpringApplication的構(gòu)造函數(shù)參數(shù)是Spring bean的配置源周拐。 在大多數(shù)情況下,它們是對@Configuration類的引用凰兑,但它們也可以是對XML配置或應(yīng)掃描的程序包的引用妥粟。
可以在application.properties中配置你的SpringApplication,詳情見參見外部化配置
有關(guān)配置選項的完整列表,請參見SpringApplication Javadoc吏够。
4.1.5 流式構(gòu)建API
如果您需要構(gòu)建ApplicationContext層次結(jié)構(gòu)(具有父/子關(guān)系的多個上下文)勾给,或者如果您更喜歡使用“流式的”構(gòu)建器API,則可以使用SpringApplicationBuilder锅知。
SpringApplicationBuilder允許您將多個方法調(diào)用鏈接在一起播急,并包括允許您創(chuàng)建層次結(jié)構(gòu)的父方法和子方法,如以下示例所示:
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
創(chuàng)建ApplicationContext層次結(jié)構(gòu)時有一些限制售睹。 例如桩警,Web組件必須包含在子上下文中,并且相同的環(huán)境用于父上下文和子上下文昌妹。 有關(guān)完整的詳細信息捶枢,請參見SpringApplicationBuilder Javadoc。
4.1.6 應(yīng)用程序事件和監(jiān)聽器
除了通常的Spring Framework事件(例如ContextRefreshedEvent)之外捺宗,SpringApplication還發(fā)送一些其他應(yīng)用程序事件柱蟀。
一些事件在應(yīng)用程序上下文創(chuàng)建前觸發(fā),所以你不能在這些事件中將一個Listener注冊為一個Bean蚜厉。你可以通過SpringApplication的addListener()方法或SpringApplicationBuilder的listeners()方法來注冊它們长已。
如果你希望這些Listeners被自動注冊,而不用去管應(yīng)用以何種方式創(chuàng)建,你可以在工程中添加一個META-INF/spring.factories文件并通過org.springframework.context.ApplicationListener來引用它們术瓮,像下面展示的這樣:
org.springframework.context.ApplicationListener=com.example.project.MyListener
當應(yīng)用啟動時康聂,應(yīng)用事件按照下列順序發(fā)送:
- ApplicationStartingEvent在運行開始時發(fā)送,但在進行任何處理之前(偵聽器和初始化程序的注冊除外)發(fā)送胞四。
- 當已知要在上下文中使用的環(huán)境但在創(chuàng)建上下文之前恬汁,將發(fā)送ApplicationEnvironmentPreparedEvent。
- 準備ApplicationContext并調(diào)用ApplicationContextInitializers之后但在加載任何bean定義之前辜伟,將發(fā)送ApplicationContextInitializedEvent氓侧。
- 在刷新開始之前但在加載bean定義之后發(fā)送ApplicationPreparedEvent。
- 在刷新上下文之后但在調(diào)用任何應(yīng)用程序和命令行運行程序之前导狡,發(fā)送ApplicationStartedEvent约巷。
- 在調(diào)用任何應(yīng)用程序和命令行運行程序之后,將發(fā)送ApplicationReadyEvent旱捧。 它指示應(yīng)用程序已準備就緒独郎,可以處理請求。
- 如果啟動時發(fā)生異常枚赡,則發(fā)送ApplicationFailedEvent氓癌。
上面的列表僅包括綁定到SpringApplication的SpringApplicationEvents,除了上述那些贫橙,下面的事件也會在ApplicationPreparedEvent之后且在ApplicationStartedEvent之前發(fā)送贪婉。
- 刷新ApplicationContext時,將發(fā)送ContextRefreshedEvent料皇。
- WebServer準備就緒后谓松,將發(fā)送WebServerInitializedEvent。 ServletWebServerInitializedEvent和ReactiveWebServerInitializedEvent分別是servlet和反應(yīng)式變量践剂。
您通常不需要使用應(yīng)用程序事件鬼譬,但是很容易知道它們的存在。 在內(nèi)部逊脯,Spring Boot使用事件來處理各種任務(wù)优质。
應(yīng)用程序事件是通過使用Spring Framework的事件發(fā)布機制發(fā)送的。 此機制的一部分確保在子級上下文中發(fā)布給偵聽器的事件也可以在任何祖先上下文中發(fā)布給偵聽器军洼。 結(jié)果巩螃,如果您的應(yīng)用程序使用SpringApplication實例的層次結(jié)構(gòu),則偵聽器可能會收到同一類型的應(yīng)用程序事件的多個實例匕争。
為了使您的偵聽器能夠區(qū)分其上下文的事件和后代上下文的事件避乏,它應(yīng)請求注入其應(yīng)用程序上下文,然后將注入的上下文與事件的上下文進行比較甘桑。 可以通過實現(xiàn)ApplicationContextAware來注入上下文拍皮,或者歹叮,如果偵聽器是bean,則可以使用@Autowired注入上下文铆帽。
4.1.7 Web環(huán)境
SpringApplication嘗試代表您創(chuàng)建正確的ApplicationContext類型咆耿,用于確定WebApplicationType的算法非常簡單:
- 如果存在Spring MVC,則使用AnnotationConfigServletWebServerApplicationContext
- 如果不存在Spring MVC并且存在Spring WebFlux爹橱,則使用AnnotationConfigReactiveWebServerApplicationContext
-否則使用AnnotationConfigApplicationContext
這意味著萨螺,如果您在同一應(yīng)用程序中使用Spring MVC和Spring WebFlux中的新WebClient,則默認情況下將使用Spring MVC愧驱。 您可以通過調(diào)用setWebApplicationType(WebApplicationType)輕松覆蓋它慰技。
也可以通過調(diào)用setApplicationContextClass(…?)來完全控制ApplicationContext類型。
在JUnit測試中使用SpringApplication時冯键,通常希望調(diào)用setWebApplicationType(WebApplicationType.NONE)施符。
4.1.8 接收應(yīng)用參數(shù)
如果您需要訪問傳遞給SpringApplication.run(...)的應(yīng)用程序參數(shù)楞陷,則可以注入org.springframework.boot.ApplicationArguments bean。 ApplicationArguments接口提供對原始String []參數(shù)以及已解析的選項和非選項參數(shù)的訪問眼耀,如以下示例所示:
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
@Component
public class MyBean {
@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true, files=["logfile.txt"]
}
}
Spring Boot還向Spring環(huán)境注冊了CommandLinePropertySource蚯舱。 這樣改化,您還可以使用@Value批注注入單個應(yīng)用程序參數(shù)。
4.1.9 使用ApplicationRunner和CommandLineRunner
如果您在應(yīng)用啟動之后立即執(zhí)行一些特殊的代碼枉昏,您可以實現(xiàn)ApplicationRunner或CommandLineRunner接口陈肛。這兩個接口以相同的方式工作并提供一個單獨的在SpingApplication.run()完成前調(diào)用的run()方法。
CommandLineRunner接口以簡單的字符串數(shù)組提供對應(yīng)用程序參數(shù)的訪問兄裂,而ApplicationRunner使用前面討論的ApplicationArguments接口句旱。 以下示例顯示了帶有run方法的CommandLineRunner:
import org.springframework.boot.*;
import org.springframework.stereotype.*;
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
如果多個CommandLineRunner或ApplicationRunner的Bean被定義,它們必須以順序的方式調(diào)用晰奖,你可以實現(xiàn)org.springframework.core.ordered接口或是使用org.springframework.core.annotation.Order注解
4.1.10 應(yīng)用退出
每個SpringApplication向JVM注冊一個關(guān)閉鉤子谈撒,以確保ApplicationContext在退出時正常關(guān)閉。 可以使用所有標準的Spring生命周期回調(diào)(例如DisposableBean接口或@PreDestroy批注)匾南。
另外啃匿,如果bean希望在調(diào)用SpringApplication.exit()時返回特定的退出代碼,則可以實現(xiàn)org.springframework.boot.ExitCodeGenerator接口蛆楞。 然后可以將此退出代碼傳遞給System.exit()溯乒,以將其作為狀態(tài)代碼返回,如以下示例所示:
@SpringBootApplication
public class ExitCodeApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args)));
}
}
另外豹爹,ExitCodeGenerator接口可以通過異常實現(xiàn)裆悄。 遇到此類異常時,Spring Boot返回實現(xiàn)的getExitCode()方法提供的退出代碼臂聋。
4.1.11 管理員功能
通過指定spring.application.admin.enabled屬性光稼,可以為應(yīng)用程序啟用與管理員相關(guān)的功能崖技。 這將在平臺MBeanServer上公開SpringApplicationAdminMXBean。 您可以使用此功能來遠程管理Spring Boot應(yīng)用程序钟哥。 對于任何服務(wù)包裝器實現(xiàn)迎献,此功能也可能很有用。
如果您想知道應(yīng)用程序在哪個HTTP端口上運行腻贰,請使用local.server.port鍵獲取屬性吁恍。
4.2 外部配置
Spring Boot使您可以外部化配置,以便可以在不同環(huán)境中使用相同的應(yīng)用程序代碼播演。 您可以使用properties文件冀瓦,YAML文件,環(huán)境變量和命令行參數(shù)來外部化配置写烤。 可以使用@Value批注將屬性值直接注入到您的bean中翼闽,可以通過Spring的Environment抽象訪問,也可以通過@ConfigurationProperties綁定到結(jié)構(gòu)化對象洲炊。
Spring Boot使用一個非常特殊的PropertySource順序感局,該順序旨在允許合理地覆蓋值。屬性應(yīng)該按照下列的順序:
- 當使用devtools時暂衡,$ HOME / .config / spring-boot文件夾中的Devtools全局設(shè)置屬性询微。
- 測試用例上的@TestPropertySource注解
- 測試用例上的properties屬性。在@SpringBootTest和測試注釋上可用狂巢,用于測試應(yīng)用程序的特定部分撑毛。
- 命令行參數(shù)。
- 來自SPRING_APPLICATION_JSON的屬性(嵌入在環(huán)境變量或系統(tǒng)屬性中的內(nèi)聯(lián)JSON)唧领。
- ServletConfig初始化參數(shù)藻雌。
- ServletContext初始化參數(shù)。
- java:comp/env中的JNDI屬性斩个。
- Java系統(tǒng)屬性(System.getProperties())胯杭。
- 操作系統(tǒng)環(huán)境變量。
- 一個RandomValuePropertySource萨驶,僅具有random.*屬性歉摧。
- 打包的jar之外的特定于配置文件的應(yīng)用程序?qū)傩裕╝pplication- {profile} .properties和YAML變體)。
- 打包在jar中的[特定于配置文件])(https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/htmlsingle/#boot-features-external-config-profile-specific-properties)的應(yīng)用程序?qū)傩裕╝pplication- {profile} .properties和YAML變體)腔呜。
- 打包的jar之外的應(yīng)用程序?qū)傩裕╝pplication.properties和YAML變體)叁温。
- 打包在jar中的應(yīng)用程序?qū)傩裕╝pplication.properties和YAML變體)。
- @Configuration類上的@PropertySource注解核畴。 請注意膝但,在刷新應(yīng)用程序上下文之前,不會將此類屬性源添加到環(huán)境中谤草。 現(xiàn)在配置某些屬性(如loggin.*和spring.main.*)為時已晚跟束,這些屬性在刷新開始之前就已讀取莺奸。
- 默認屬性(通過設(shè)置SpringApplication.setDefaultProperties指定)。
提供一個具體的例子冀宴,假設(shè)你正在開發(fā)一個使用了一個name屬性的@Component灭贷,像下面這樣:
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
}
在您的應(yīng)用程序類路徑上(例如,在jar內(nèi))略贮,您可以擁有一個application.properties文件甚疟,該文件為名稱提供合理的默認屬性值。 在新環(huán)境中運行時逃延,可以在jar外部提供一個覆蓋名稱的application.properties文件览妖。 對于一次性測試,可以使用特定的命令行開關(guān)啟動(例如揽祥,java -jar app.jar --name =“ Spring”)讽膏。
可以在命令行中使用環(huán)境變量來提供SPRING_APPLICATION_JSON屬性。 例如拄丰,您可以在UN * X shell中使用以下行:
$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar
在前面的示例中府树,您最終在Spring Environment中獲得了acme.name = test。 您還可以在System屬性中將JSON作為spring.application.json提供愈案,如以下示例所示:
$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
您還可以使用命令行參數(shù)來提供JSON挺尾,如以下示例所示:
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'
您還可以將JSON作為JNDI變量提供,如下所示:
java:comp / env / spring.application.json站绪。
4.2.1 配置任意值
RandomValuePropertySource可用于注入隨機值(例如,秘鑰或測試案例)丽柿,它可以生成integers,longs,uuids恢准,或者strings,如下所示:
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,35536]}
random.int*語法是OPEN value(,max ) CLOSE甫题,其中OPEN馁筐,CLOSE是任何字符,value坠非,max是整數(shù)敏沉。 如果提供了max,則value是最小值炎码,而max是最大值(不包括)盟迟。
4.2.2 獲取命令行屬性
默認SpringApplicatin轉(zhuǎn)換任何命令行可選參數(shù)(參數(shù)以--開始,例如--server.port=9000)到一個屬性并將其添加到Spring Environment抽象中潦闲。正如前面提到過的攒菠,命令行參數(shù)總數(shù)優(yōu)先于其它屬性源。
如果你不想將你的命令行參數(shù)添加到Environment,你可以通過SpringApplicaton.setAddCommandLineProperties(false)來關(guān)閉它歉闰。
4.2.3 應(yīng)用程序文件
SpringApplicaton從下面位置的application.properties文件加載屬性并將其添加到Spring環(huán)境中:
- 在當前目錄的一個/config子目錄
- 當前目錄
- 類路徑中的/config包
- 根類路徑
該列表按照優(yōu)先級排列(在優(yōu)先級高的位置定義的屬性會覆寫那些在低優(yōu)先級位置定義的)
您也可以用YAML文件來替代.properties文件
如果你不喜歡application.properties作為配置文件名稱辖众,你也可以指定spring.config.name環(huán)境屬性切換到其它的文件卓起。你同樣可以通過spring.config.location環(huán)境屬性來引用一個外部的位置(用逗號分隔的目錄或文件路徑列表),下面示例展示了如何指定一個不同的文件名稱:
$ java -jar myproject.jar --spring.config.name=myproject
下面示例展示了如何指定兩個位置:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
spring.config.name和spring.config.location在最開始就被用來決定那些文件應(yīng)被加載,它們必須作為環(huán)境屬性被定義(通常是操作系統(tǒng)環(huán)境變量凹炸,一個系統(tǒng)屬性戏阅,或是命令行參數(shù))
如果Spring.config.location包含目錄(而不是文件),那應(yīng)該以/結(jié)束(并在運行之前啤它,在從spring.config.name中生成的文件名被加載之前奕筐,附加在生成的文件之后,包含特定配置文件的文件名)蚕键。spring.config.location中指定的文件按原樣使用救欧,不支持特定配置文件的變體,并且被任何特定配置文件的屬性覆蓋锣光。
配置目錄按反向順序搜索笆怠。默認配置文件位置是 classpath:/,classpath:/config/,file:./,file:./config/,結(jié)果搜索順序如下:
- file:/config/
- file:./
- classpath:/config/
- classpath:/
使用spring.config.location配置自定義配置位置后,它們將替換默認位置誊爹。例如蹬刷,如果spring.config.location按classpath:/custom-config/,file:./custom-config/配置,搜索順序變成下列所示:
- file:./custom-config/
- classpath:custom-config/
另外频丘,當使用spring.config.additional-location配置自定義配置位置時办成,除默認位置外,還會使用它們搂漠。 在默認位置之前搜索其他位置迂卢。 例如,如果配置了classpath:/ custom-config/桐汤,file:./custom-config/的其他位置而克,則搜索順序如下:
- file:/custom-config/
- classpath:custom-config/
- file:./config/
- file:./
- classpath:/config/
- classpath:/
搜索順序允許你在一個配置文件中指定一些默認值然后再其它配置文件中選擇性的覆寫那些值。您可以在默認位置之一的application.properties(或使用spring.config.name選擇的其他任何基本名稱)中為應(yīng)用程序提供默認值怔毛。然后员萍,可以在運行時使用自定義位置之一中的其他文件覆蓋這些默認值。
如果你使用環(huán)境變量而不是系統(tǒng)變量拣度,大多數(shù)操作系統(tǒng)不允許使用句點分隔的鍵名碎绎,但是可以使用下劃線代替(例如,使用SPRING_CONFIG_NAME代替spring.config.name)抗果。
如果您的應(yīng)用程序在容器中運行筋帖,則可以使用JNDI屬性(在java:comp / env中)或servlet上下文初始化參數(shù)代替環(huán)境變量或系統(tǒng)屬性,也可以使用它窖张。
4.2.4 特定于配置文件的屬性
除了application.properties文件之外幕随,還可以使用以下命名約定來定義特定于配置文件的屬性:application- {profile} .properties。 如果沒有設(shè)置活動配置文件宿接,則環(huán)境具有一組默認配置文件(默認為[default])赘淮。 換句話說辕录,如果未顯式激活任何配置文件,那么將加載application-default.properties中的屬性梢卸。
特定于配置文件的屬性是從與標準application.properties相同的位置加載的走诞,特定于配置文件的文件總是會覆蓋非特定文件,無論特定于配置文件的文件是位于打包jar的內(nèi)部還是外部蛤高。
如果指定了多個配置文件蚣旱,則采用后贏策略。 例如戴陡,在通過SpringApplication API配置了配置文件之后塞绿,添加了spring.profiles.active屬性指定的配置文件,其具有優(yōu)先權(quán)恤批。
如果您在spring.config.location中指定了任何文件异吻,則不考慮這些文件的特定于配置文件的變體。 如果您還想使用特定于配置文件的屬性喜庞,請使用spring.config.location中的目錄诀浪。
4.2.5 屬性中的占位符
使用application.properties中的值時,它們會通過現(xiàn)有環(huán)境進行過濾延都,因此您可以參考以前定義的值(例如雷猪,從System屬性中)。
app.name=MyApp
app.description=${app.name} is a Spring Boot application
您還可以使用此技術(shù)來創(chuàng)建現(xiàn)有Spring Boot屬性的“簡短”變體晰房。 有關(guān)詳細信息求摇,請參見使用“簡短”命令行參數(shù)方法。
4.2.6 加密屬性
Spring Boot不提供對加密屬性值的任何內(nèi)置支持殊者,但是月帝,它確實提供了修改Spring環(huán)境中包含的值所必需的掛鉤點。EnvironmentPostProcessor界面允許您在應(yīng)用程序啟動之前操縱Environment幽污。 有關(guān)詳細信息,請參見在啟動前自定義環(huán)境或ApplicationContext簿姨。
如果您正在尋找一種安全的方式來存儲憑據(jù)和密碼距误,則Spring Cloud Vault項目提供了對在HashiCorp Vault中存儲外部化配置的支持。
4.2.7 使用YAML代替Properties
YAML是JSON的超集扁位,因此是一種用于指定層次結(jié)構(gòu)配置數(shù)據(jù)的便捷格式准潭。只要在類路徑上具有SnakeYAML庫,SpringApplication類就會自動支持YAML作為Properties的替代域仇。
如果你使用了“Starters”,spring-boot-starter已經(jīng)自動提供了SnakeYAML刑然。
加載YAML
Spring Framework提供了兩個便捷的類可以用來加載YAML文檔。YamlPropertiesFactoryBean將YAML作為Properties加載暇务,而YamlMapFactoryBean將YAML作為Map加載泼掠。
例如怔软,思考下面的YAML文檔:
environments:
dev:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App
上述示例將被轉(zhuǎn)換成下列屬性:
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
YAML列表用[index]解引用器表示為屬性鍵。例如择镇,思考下面的YAML:
my:
servers:
- dev.example.com
- another.example.com
上述的示例將被轉(zhuǎn)換為下述屬性:
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
要使用Spring Boot的Binder實用程序(@ConfigurationProperties所做的)綁定到類似的屬性挡逼,您需要在目標bean中擁有一個類型為java.util.List(或Set)的屬性,或者您需要提供一個setter 或使用可變值對其進行初始化腻豌。 例如家坎,以下示例綁定到前面顯示的屬性:
@ConfigurationProperties(prefix="my")
public class Config {
private List<String> servers = new ArrayList<String>();
public List<String> getServers() {
return this.servers;
}
}
在Spring環(huán)境中將YAML公開為屬性
YamlPropertySourceLoader類可用于在Spring環(huán)境中將YAML公開為PropertySource。 這樣做可以讓您使用@Value批注和占位符語法來訪問YAML屬性吝梅。
多個特定配置的YAML文件
您可以使用spring.profiles鍵在一個文件中指定多個特定于配置文件的YAML文檔虱疏,以指示何時應(yīng)用該文檔,如以下示例所示:
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120
在前面的示例中苏携,如果開發(fā)配置文件處于活動狀態(tài)做瞪,則server.address屬性為127.0.0.1。 同樣兜叨,如果生產(chǎn)和eu-central配置文件處于活動狀態(tài)穿扳,則server.address屬性為192.168.1.120。 如果未啟用開發(fā)国旷,生產(chǎn)和其他中心配置文件矛物,則該屬性的值為192.168.1.100。
因此spring.profiles可以包含一個簡單的概要文件名稱(例如生產(chǎn))或概要文件表達式跪但。 配置文件表達式允許表達更復(fù)雜的配置文件邏輯履羞,例如production&(eu-central | eu-west)。 有關(guān)更多詳細信息屡久,請參閱參考指南忆首。
如果在啟動應(yīng)用程序上下文時未顯式激活任何活動,則會激活默認配置文件被环。 因此糙及,在以下YAML中,我們?yōu)閟pring.security.user.password設(shè)置了一個值筛欢,該值僅在“默認”配置文件中可用:
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
而在以下示例中浸锨,始終設(shè)置密碼是因為該密碼未附加到任何配置文件,并且必須根據(jù)需要在所有其他配置文件中將其顯式重置:
server:
port: 8000
spring:
security:
user:
password: weak
通過使用spring.profiles指定的Spring文件可以選擇用'!'來否定版姑。如果在一個文檔中未否定和否定的profile同時存在的話柱搜,最后一個未否定文件必須匹配,并且可能沒有否定文件可以匹配剥险。
YAML缺點
無法使用@PropertySource注解加載YAML文件聪蘸。 因此,在需要以這種方式加載值的情況下,需要使用屬性文件健爬。
在特定于配置文件的YAML文件中使用多YAML文檔語法可能會導(dǎo)致意外行為控乾。 例如,考慮文件中的以下配置:
server:
port: 8000
---
spring:
profiles: "!test"
security:
user:
password: "secret"
如果使用參數(shù)--spring.profiles.active = dev運行應(yīng)用程序浑劳,則可能希望將security.user.password設(shè)置為“ secret”阱持,但事實并非如此。
嵌套文檔將被過濾魔熏,因為主文件名為application-dev.yml衷咽。 它已經(jīng)被認為是特定于配置文件的,并且嵌套文檔將被忽略蒜绽。
我們建議您不要混用特定于配置文件的YAML文件和多個YAML文檔镶骗。 堅持只使用其中之一。
4.2.8 類型安全的配置屬性
使用@Value(${property}”)注解來注入配置屬性有時會很麻煩躲雅,尤其是當您使用多個屬性或數(shù)據(jù)本質(zhì)上是分層的時鼎姊。 Spring Boot提供了一種使用屬性的替代方法,該方法使強類型的Bean可以管理和驗證應(yīng)用程序的配置相赁。
JavaBean屬性綁定
可以綁定一個聲明標準JavaBean屬性的bean相寇,如以下示例所示:
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() { ... }
public void setEnabled(boolean enabled) { ... }
public InetAddress getRemoteAddress() { ... }
public void setRemoteAddress(InetAddress remoteAddress) { ... }
public Security getSecurity() { ... }
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() { ... }
public void setUsername(String username) { ... }
public String getPassword() { ... }
public void setPassword(String password) { ... }
public List<String> getRoles() { ... }
public void setRoles(List<String> roles) { ... }
}
}
上述的POJO定義了下列屬性:
- acme.enabled, 默認值為false。
- acme.remote-address, 具有可以從String強制轉(zhuǎn)換的類型钮科。
- acme.security.username,帶有嵌套的“安全”對象唤衫,其名稱由屬性名稱決定。 特別是绵脯,返回類型根本不使用佳励,可能是SecurityProperties。
- acme.security.password蛆挫。
- acme.security.roles,帶有默認為"USER"的String集合赃承。
映射到Spring Boot中可用的@ConfigurationProperties類的屬性(通過屬性文件,YAML文件悴侵,環(huán)境變量等進行配置)是公共API瞧剖,但是該類本身的訪問器(獲取器/設(shè)置器)不能直接使用。
這種安排依賴于默認的空構(gòu)造函數(shù)可免,并且getter和setter通常是強制性的筒繁,因為綁定是通過標準Java Beans屬性描述符進行的,就像在Spring MVC中一樣巴元。 在以下情況下,可以忽略setter:
- Map,只要初始化驮宴,它們就需要使用getter逮刨,但不一定需要使用setter,因為它們可以被binder改變。
- 集合和數(shù)組可以通過下標(通常是YAML)或一個逗號分隔的值來訪問修己,在后面的例子中恢总,setter是必須的。我們建議你為這種類型總是添加一個setter睬愤。如果你初始化了一個集合片仿,確保它是不可變的(像上述示例一樣)
- 如果嵌套的POJO屬性被初始化了(像上述示例中的Security一樣),setter并不是必須的尤辱。如果希望binder通過使用其默認構(gòu)造函數(shù)動態(tài)創(chuàng)建實例砂豌,則需要一個setter。
一些人使用Lombok項目來自動添加getters和setters光督。確保Lombok不會為這樣的類型添加人惡化特殊構(gòu)造器阳距,因為容器會自動使用它實例化對象。
最后结借,只有標準Java Bean屬性可以筐摘,綁定到靜態(tài)屬性是不被支持的。
構(gòu)造器綁定
上一節(jié)中的示例可以以不變的方式重寫船老,如下例所示:
package com.example;
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
在此設(shè)置中咖熟,@ConstructorBinding注解用于指示應(yīng)使用構(gòu)造函數(shù)綁定。 這意味著綁定器將期望找到帶有您希望綁定的參數(shù)的構(gòu)造函數(shù)柳畔。
@ConstructorBinding類的嵌套成員(例如上例中的Security)也將通過其構(gòu)造函數(shù)進行綁定馍管。
可以使用@DefaultValue指定默認值,并且將應(yīng)用相同的轉(zhuǎn)換服務(wù)將String值強制為缺少屬性的目標類型荸镊。
要使用構(gòu)造函數(shù)綁定咽斧,必須使用@EnableConfigurationProperties或配置屬性掃描來啟用該類。 您不能對通過常規(guī)Spring機制創(chuàng)建的bean使用構(gòu)造函數(shù)綁定(例如@Component bean躬存,通過@Bean方法創(chuàng)建的bean或使用@Import加載的bean)
如果您的類具有多個構(gòu)造函數(shù)张惹,則還可以直接在應(yīng)綁定的構(gòu)造函數(shù)上使用@ConstructorBinding。
啟用@ConfigurationProperties注解的類型
Spring Boot提供了綁定@ConfigurationProperties類型并將其注冊為Bean的基礎(chǔ)架構(gòu)岭洲。 您可以逐類啟用配置屬性宛逗,也可以啟用與組件掃描類似的方式進行配置屬性掃描。
有時盾剩,用@ConfigurationProperties注釋的類可能不適合掃描雷激,例如,如果您正在開發(fā)自己的自動配置告私,或者想要有條件地啟用它們屎暇。 在這些情況下,請使用@EnableConfigurationProperties注解指定要處理的類型列表驻粟。 可以在任何@Configuration類上完成此操作根悼,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
要使用配置屬性掃描,請將@ConfigurationPropertiesScan批注添加到您的應(yīng)用程序。 通常挤巡,它被添加到以@SpringBootApplication注釋的主應(yīng)用程序類中剩彬,但是可以將其添加到任何@Configuration類中。 默認情況下矿卑,將從聲明注釋的類的包中進行掃描喉恋。 如果要定義要掃描的特定程序包,可以按照以下示例所示進行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
使用配置屬性掃描或通過@EnableConfigurationProperties注冊@ConfigurationProperties Bean時母廷,該Bean具有常規(guī)名稱:<prefix>-<fqn>轻黑,其中<prefix>是@ConfigurationProperties批注和<fqn>中指定的環(huán)境鍵前綴。 是Bean的完全限定名稱徘意。 如果注釋不提供任何前綴苔悦,則僅使用Bean的完全限定名稱。
上例中的bean名稱是acme-com.example.AcmeProperties椎咧。
我們建議@ConfigurationProperties僅處理環(huán)境玖详,尤其不要從上下文中注入其他bean。 對于極端情況勤讽,可以使用setter注入或框架提供的任何* Aware接口(例如蟋座,需要訪問Environment的EnvironmentAware)。 如果仍要使用構(gòu)造函數(shù)注入其他bean脚牍,則必須使用@Component注釋配置屬性bean向臀,并使用基于JavaBean的屬性綁定。
使用@ConfigurationProperties注解的類型
這種配置樣式與SpringApplication外部YAML配置特別有效诸狭,如以下示例所示:
# application.yml
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
# additional configuration as required
要使用@ConfigurationProperties Bean券膀,可以像其他任何Bean一樣注入它們,如以下示例所示:
@Service
public class MyService {
private final AcmeProperties properties;
@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}
使用@ConfigurationProperties還可讓您生成元數(shù)據(jù)文件驯遇,IDE可以使用這些元數(shù)據(jù)文件為您自己的鍵提供自動完成功能芹彬。 有關(guān)詳細信息,請參見附錄叉庐。
第三方配置
除了使用@ConfigurationProperties注釋類外舒帮,還可以在公共@Bean方法上使用它。 當您要將屬性綁定到控件之外的第三方組件時陡叠,這樣做特別有用玩郊。
要從Environment屬性配置Bean,請將@ConfigurationProperties添加到其Bean注冊中枉阵,如以下示例所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
用"another"前綴定義的任何JavaBean屬性都以類似于前面的AcmeProperties示例的方式映射到該AnotherComponent bean译红。
寬松綁定
Spring Boot使用一些寬松的規(guī)則將Environment屬性綁定到@ConfigurationProperties bean,因此環(huán)境屬性名稱和bean屬性名稱之間不需要完全匹配兴溜。 有用的常見示例包括破折號分隔的環(huán)境屬性(例如临庇,context-path綁定到contextPath)和大寫的環(huán)境屬性(例如PORT綁定到端口)蠕蚜。
例如么夫,考慮以下@ConfigurationProperties類:
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
使用前面的代碼,可以全部使用以下屬性名稱:
Table 5. relaxed binding
Property | Note |
---|---|
acme.my-project.person.first-name | Kebab大小寫哪工,建議在.properties和.yml文件中使用 |
acme.myProject.person.firstName | 標準駝峰語法 |
acme.my_project.person.first_name | 下劃線表示法斋攀,是.properties和.yml文件中使用的另一種格式已卷。 |
ACME_MYPROJECT_PERSON_FIRSTNAME | 大寫格式,使用系統(tǒng)環(huán)境變量時建議使用淳蔼。 |
注釋的前綴值必須為小寫kebab格式,并用-分隔侧蘸,例如acme.my-project.person。
綁定到Map屬性時鹉梨,如果鍵包含小寫字母數(shù)字字符或-以外的任何其他字符讳癌,則需要使用方括號表示法,以便保留原始值存皂。 如果鍵沒有被[]包圍晌坤,則所有非字母數(shù)字或-的字符都將被刪除。 例如旦袋,考慮將以下屬性綁定到Map:
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3
上面的屬性將以/ key1骤菠,/ key2和key3作為map中的鍵綁定到Map。
對于YAML文件疤孕,方括號必須用引號引起來商乎,以便正確解析鍵值。
合并復(fù)雜屬性
如果在多個位置配置了列表祭阀,則通過替換整個列表來進行覆蓋鹉戚。
例如,假設(shè)MyPojo對象的名稱和描述屬性默認為空专控。 下面的示例從AcmeProperties公開MyPojo對象的列表:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考慮以下配置:
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name
如果dev配置文件未處于活動狀態(tài)抹凳,則AcmeProperties.list包含一個MyPojo條目,如先前所定義踩官。 但是却桶,如果啟用了dev配置文件,則該列表仍僅包含一個條目(名稱為我的另一個名稱蔗牡,并且描述為null)颖系。 此配置不會將第二個MyPojo實例添加到列表中,并且不會合并項目辩越。
在多個配置文件中指定列表時嘁扼,將使用優(yōu)先級最高的列表(并且僅使用那個列表)。 考慮以下示例:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name
在前面的示例中黔攒,如果dev配置文件處于活動狀態(tài)趁啸,則AcmeProperties.list包含一個MyPojo條目(其名稱為my的另一個名稱强缘,以及為null的描述。對于YAML不傅,可以使用逗號分隔的列表和YAML列表來完全覆蓋列表的內(nèi)容旅掂。
對于Map屬性,可以綁定從多個來源繪制的屬性值访娶。 但是商虐,對于多個源中的同一屬性,將使用優(yōu)先級最高的屬性崖疤。 下面的示例從AcmeProperties公開Map <String秘车,MyPojo>:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
考慮以下配置:
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
如果開發(fā)人員配置文件未處于活動狀態(tài),則AcmeProperties.map包含一個鍵為key1的條目(名稱為我的名字1劫哼,描述為my description 1)叮趴。但是,如果啟用了開發(fā)配置文件权烧,則map包含兩個條目眯亦,其中鍵為key1(名稱為dev name 1,其描述為my description 1)和key2(名稱為dev name 2豪嚎,其描述為dev description 2)搔驼。
前述合并規(guī)則不僅適用于YAML文件,而且適用于所有屬性源中的屬性侈询。
屬性轉(zhuǎn)換
當Spring Boot綁定到@ConfigurationProperties bean時舌涨,它嘗試將外部應(yīng)用程序?qū)傩詮娭茷檎_的類型。 如果需要自定義類型轉(zhuǎn)換扔字,則可以提供一個ConversionService bean(具有一個名為conversionService的bean)或自定義屬性編輯器(通過CustomEditorConfigurer bean)或自定義Converters(具有定義為@ConfigurationPropertiesBinding的bean定義)囊嘉。
由于在應(yīng)用程序生命周期中非常早就請求了此bean,因此請確保限制您的ConversionService使用的依賴項革为。 通常扭粱,您需要的任何依賴項在創(chuàng)建時可能都沒有完全初始化。 如果配置鍵強轉(zhuǎn)不需要自定義ConversionService震檩,而僅依賴于具有@ConfigurationPropertiesBinding限定的自定義轉(zhuǎn)換器琢蛤,則可能需要重命名自定義ConversionService。
轉(zhuǎn)換Duration
Spring Boot為表達持續(xù)時間提供了專門的支持抛虏。 如果公開java.time.Duration屬性博其,則應(yīng)用程序?qū)傩灾械囊韵赂袷娇捎茫?/p>
- 常規(guī)的長表示形式(使用毫秒作為默認單位,除非已指定@DurationUnit)
- java.time.Duration使用的標準ISO-8601格式
- 值和單位相結(jié)合的更易讀的格式(例如10s表示10秒)
考慮下面的格式:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
要指定30秒的會話超時迂猴,則30慕淡,PT30S和30s都是等效的。 可以使用以下任意形式指定500ms的讀取超時:500沸毁,PT0.5S和500ms峰髓。
您也可以使用任何受支持的單位傻寂。 這些是:
- ns,納秒
- us,微秒
- ms,毫秒
- s,秒
- m,分鐘
- h,小時
- d,天
默認單位是毫秒,可以使用@DurationUnit覆蓋携兵,如上面的示例所示疾掰。
如果您要從僅使用Long表示持續(xù)時間的先前版本進行升級,請確保在轉(zhuǎn)換為Duration的旁邊沒有毫秒數(shù)的情況下定義單位(使用@DurationUnit)徐紧。 這樣做可以提供透明的升級路徑个绍,同時支持更豐富的格式。
轉(zhuǎn)換數(shù)據(jù)大小
Spring Framework具有DataSize值類型浪汪,以字節(jié)為單位表示大小。 如果公開DataSize屬性凛虽,則應(yīng)用程序?qū)傩灾械囊韵赂袷娇捎茫?/p>
- 常規(guī)的長表示形式(除非已指定@DataSizeUnit死遭,否則使用字節(jié)作為默認單位)
- 值和單位耦合在一起的更易讀的格式(例如10MB表示10兆字節(jié))
考慮下面的格式:
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
public DataSize getBufferSize() {
return this.bufferSize;
}
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
}
}
若要指定10MB的緩沖區(qū)大小,則10和10MB是等效的凯旋。256個字節(jié)的大小閾值可以指定為256或256B呀潭。
您也可以使用任何受支持的單位。 這些是:
- B, bytes
- KB, kilobytes
- MB, megabytes
- GB, gigabytes
- TB, terabytes
默認單位是字節(jié)至非,可以使用@DataSizeUnit覆蓋钠署,如上面的示例所示。
如果您要從僅使用Long表示大小的先前版本進行升級荒椭,請確保在切換到DataSize旁邊沒有字節(jié)的情況下定義單位(使用@DataSizeUnit)谐鼎。 這樣做可以提供透明的升級路徑,同時支持更豐富的格式趣惠。
@ConfigurationProperties驗證
每當使用Spring的@Validated注解對@ConfigurationProperties類進行注釋時狸棍,Spring Boot就會嘗試對其進行驗證。 您可以在配置類上直接使用JSR-303 javax.validation約束注釋味悄。 為此草戈,請確保在類路徑上有兼容的JSR-303實現(xiàn),然后將約束注釋添加到字段中侍瑟,如以下示例所示:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
您還可以通過使用@Validated注釋創(chuàng)建配置屬性的@Bean方法來觸發(fā)驗證唐片。
為了確保始終為嵌套屬性觸發(fā)驗證,即使未找到任何屬性涨颜,也必須使用@Valid注釋關(guān)聯(lián)的字段费韭。 以下示例基于前面的AcmeProperties示例:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
// ... getters and setters
public static class Security {
@NotEmpty
public String username;
// ... getters and setters
}
}
您還可以通過創(chuàng)建一個名為configurationPropertiesValidator的bean定義來添加自定義的Spring Validator。 @Bean方法應(yīng)聲明為靜態(tài)咐低。 配置屬性驗證器是在應(yīng)用程序生命周期的早期創(chuàng)建的揽思,并且將@Bean方法聲明為static可以使創(chuàng)建該Bean而不必實例化@Configuration類。 這樣做避免了由早期實例化引起的任何問題见擦。
spring-boot-actuator模塊包括一個公開所有@ConfigurationProperties bean的端點钉汗。 將您的Web瀏覽器指向/ actuator / configprops或使用等效的JMX端點羹令。 有關(guān)詳細信息,請參見“生產(chǎn)就緒功能”部分损痰。
@ConfigurationProperties與@Value
@Value批注是核心容器功能福侈,它沒有提供與類型安全的配置屬性相同的功能。 下表總結(jié)了@ConfigurationProperties和@Value支持的功能:
Feature | @ConfigurationProperties | @Value |
---|---|---|
Relaxed binding | Yes | No |
Meta-data support | Yes | No |
SpEL evaluation | No | Yes |
如果您為自己的組件定義了一組配置鍵卢未,我們建議您將它們組合在以@ConfigurationProperties注釋的POJO中肪凛。 您還應(yīng)該意識到,由于@Value不支持寬松的綁定辽社,因此如果您需要使用環(huán)境變量來提供值伟墙,則它不是一個很好的選擇。
最后滴铅,盡管您可以在@Value中編寫SpEL表達式戳葵,但不會從應(yīng)用程序?qū)傩晕募?/a>中處理此類表達式。
4.3 Profiles
Spring Profiles提供了一種隔離應(yīng)用程序配置部分并使之僅在某些環(huán)境中可用的方法汉匙。 可以使用@Profile標記任何@ Component拱烁,@ Configuration或@ConfigurationProperties,以限制其加載時間噩翠,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@Profile("production")
public class ProductionConfiguration {
// ...
}
如果@ConfigurationProperties Bean是通過@EnableConfigurationProperties而非自動掃描注冊的戏自,則需要在具有@EnableConfigurationProperties注解的@Configuration類上指定@Profile注解。在掃描@ConfigurationProperties的情況下伤锚,可以在@ConfigurationProperties類本身上指定@Profile擅笔。
你可以通過spring.profiles.active環(huán)境屬性來指定哪個profile處于激活狀態(tài),你可以通過本章前面介紹的任何方式指定屬性见芹。 例如剂娄,你可以將其包含在application.properties中,如以下示例所示:
spring.profiles.avtive=dev,hsqldb
您也可以使用以下開關(guān)在命令行上指定它:--spring.profiles.avtive=dev,hsqldb
4.3.1
spring.profiles.active屬性遵循與其他屬性相同的排序規(guī)則:最高的PropertySource獲勝玄呛。 這意味著您可以在application.properties中指定活動配置文件阅懦,然后使用命令行開關(guān)替換它們。
有時徘铝,將特定配置文件的屬性添加到活動配置文件而不是替換它們是有用的耳胎。 spring.profiles.include屬性可用于無條件添加活動配置文件。 SpringApplication入口點還具有Java API惕它,用于設(shè)置其他配置文件(即怕午,在由spring.profiles.active屬性激活的配置文件之上)。 請參閱SpringApplication中的setAdditionalProfiles()方法淹魄。
例如郁惜,使用開關(guān)--spring.profiles.active = prod運行具有以下屬性的應(yīng)用程序時,proddb和prodmq配置文件也會被激活:
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq
請記住甲锡,可以在YAML文檔中定義spring.profiles屬性兆蕉,以確定何時將該特定文檔包括在配置中羽戒。 有關(guān)更多詳細信息,請參見根據(jù)環(huán)境更改配置虎韵。
4.3.2 以編程方式設(shè)置配置文件
您可以在應(yīng)用程序運行之前通過調(diào)用SpringApplication.setAdditionalProfiles(…)以編程方式設(shè)置活動配置文件易稠。 也可以使用Spring的ConfigurableEnvironment接口來激活配置文件。
4.3.3 特定配置的配置文件
application.properties(或application.yml)和通過@ConfigurationProperties引用的文件的特定配置文件的變體都被視為文件并已加載包蓝。 有關(guān)詳細信息驶社,請參見“特定配置文件的屬性”。