最近公司項目在作SpringBoot的升級,在升級過程當中遇到了一些問題,簡單記錄一下,作個分享。另外,本文中的程序只爲示例代碼,並不是公司生產環境代碼。java
從SpringBoot1.x升級到SpringBoot2.x以後,解決完編譯異常,運行程序,在程序啓動時報錯:spring
報錯信息就已經很直白的告訴了咱們錯誤緣由:springboot
配置屬性名稱「com_shen」無效app
無效字符: '_', 緣由:規範名稱應爲kebab-case(用'-'分隔),小寫字母數字字符,而且必須以字母開頭ide
通過排查,是由於在application.properties
文件中有以下一個配置項:spring-boot
com_shen.name=xiaohei
複製代碼
對應Java程序代碼:post
@Getter
@Setter
@ConfigurationProperties(prefix = "com_shen")
public class Service {
private String name;
}
複製代碼
結合報錯日誌,咱們能夠很容易的解決這個問題,去掉配置項中的_
,將配置項name修改成com.shen.name
便可。spa
你覺得文章寫到這裏就結束了嗎?其實並無。hhhhhh,經過這個問題,咱們來看一下SpringBoot2.x的內部源碼。什麼,你不知道該從哪裏入手來看這個源碼,不要緊,咱們一步一步來。翻譯
點開@ConfigurationProperties
源碼,debug
在Spring中,大量的功能都是經過BeanPostProcessor
來實現的。並且,Spring中的源碼註釋寫的很是的仔細。經過源碼註釋咱們能夠猜到多是ConfigurationPropertiesBindingPostProcessor
這個類在負責@ConfigurationProperties
註解的背後支持。
點開ConfigurationPropertiesBindingPostProcessor
類源碼,發如今該類中Override了BeanPostProcessor
的postProcessBeforeInitialization
方法:
bind(bean, beanName, annotation);
方法。這個方法名叫"綁定",方法中傳入了bean、beanName和annotation的信息,經驗告訴我這個方法大機率就是在負責解析
@ConfigurationProperties
,進行屬性綁定。
因而,在這裏打一個條件斷點,debug運行項目:
經過debug發現的確是這個方法在進行屬性綁定。並且底層調用了org.springframework.boot.context.properties.bind.Binder#bind(String, Bindable<T>, BindHandler)
方法:
在這個bind
方法中,又調用了另外一個方法bind(ConfigurationPropertyName.of(name), target, handler);
,並且經過name
生成了ConfigurationPropertyName
對象ConfigurationPropertyName.of(name)
,經過方法名咱們能夠猜想,這個方法多是在負責解析Configuration Property Name,項目啓動的報錯信息頗有多是這個方法中拋出的。點開源碼:
發如今這個方法中,調用了InvalidConfigurationPropertyNameException.throwIfHasInvalidChars(name,ElementValidator.getInvalidChars(elementValue));
。Spring代碼命名真的是太優雅了,雖然名稱很長,可是讓源碼閱讀者一看就能明白這個方法在作什麼。
經過源碼,咱們能夠看到,在SpringBoot中對Configuration property name中的字符進行了有效性的判斷,判斷規則如上圖所示。
ElementValidator
類是ConfigurationPropertyName
的一個內部類。ConfigurationPropertyName
是SpringBoot2.0新增的一個類,讓咱們一塊兒來閱讀一下類中註釋,瞭解一下這個類:
機器翻譯結果以下:
由點分隔的元素組成的配置屬性名稱。 用戶建立的名稱能夠包含字符「 a-z」,「 0-9」)和「-」,它們必須爲小寫字母,而且必須以字母數字字符開頭。 「-」僅用於格式化,即「 foo-bar」和「 foobar」被認爲是等效的。 「 [」和「]」字符可用於表示關聯索引(即Map鍵或Collection索引。索引名稱不受限制,而且區分大小寫。
如下是一些典型示例:
spring.main.banner-mode server.hosts [0]。名稱 日誌[org.springboot] .level
咱們知道,SpringBoot中除了可使用@ConfigurationProperties
以外,還可使用@Value
。
Demo程序以下:
@Getter
@Setter
@Component
public class Service {
@Value("${com_shen.name}")
private String name;
}
複製代碼
application.properties
文件:
com_shen.name=xiaohei
複製代碼
在這種狀況下,項目依舊啓動成功了,並且成功的獲取到了com_shen.name
的屬性值。也就是說,@Value
註解中並無表達式作限制。
Property Binding in Spring Boot 2.0 : spring.io/blog/2018/0…
歡迎關注公衆號: