SpringBoot2.x升級踩坑,一個下劃線引起的血案

最近公司項目在作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

@ConfigurationProperties源碼

在Spring中,大量的功能都是經過BeanPostProcessor來實現的。並且,Spring中的源碼註釋寫的很是的仔細。經過源碼註釋咱們能夠猜到多是ConfigurationPropertiesBindingPostProcessor這個類在負責@ConfigurationProperties註解的背後支持。

點開ConfigurationPropertiesBindingPostProcessor類源碼,發如今該類中Override了BeanPostProcessorpostProcessBeforeInitialization方法:

ConfigurationPropertiesBindingPostProcessor#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方法中,又調用了另外一個方法bind(ConfigurationPropertyName.of(name), target, handler);,並且經過name生成了ConfigurationPropertyName對象ConfigurationPropertyName.of(name),經過方法名咱們能夠猜想,這個方法多是在負責解析Configuration Property Name,項目啓動的報錯信息頗有多是這個方法中拋出的。點開源碼:

org.springframework.boot.context.properties.source.ConfigurationPropertyName#of

發如今這個方法中,調用了InvalidConfigurationPropertyNameException.throwIfHasInvalidChars(name,ElementValidator.getInvalidChars(elementValue));。Spring代碼命名真的是太優雅了,雖然名稱很長,可是讓源碼閱讀者一看就能明白這個方法在作什麼。

`InvalidConfigurationPropertyNameException.throwIfHasInvalidChars方法

ElementValidator.getInvalidChars(elementValue)方法

經過源碼,咱們能夠看到,在SpringBoot中對Configuration property name中的字符進行了有效性的判斷,判斷規則如上圖所示。

ElementValidator類是ConfigurationPropertyName的一個內部類。ConfigurationPropertyName是SpringBoot2.0新增的一個類,讓咱們一塊兒來閱讀一下類中註釋,瞭解一下這個類:

ConfigurationPropertyName

機器翻譯結果以下:

由點分隔的元素組成的配置屬性名稱。 用戶建立的名稱能夠包含字符「 a-z」,「 0-9」)和「-」,它們必須爲小寫字母,而且必須以字母數字字符開頭。 「-」僅用於格式化,即「 foo-bar」和「 foobar」被認爲是等效的。 「 [」和「]」字符可用於表示關聯索引(即Map鍵或Collection索引。索引名稱不受限制,而且區分大小寫。

如下是一些典型示例:

spring.main.banner-mode server.hosts [0]。名稱 日誌[org.springboot] .level

使用@Value

咱們知道,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…


歡迎關注公衆號:

Coder小黑
相關文章
相關標籤/搜索