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


最近公司項目在做SpringBoot的升級,在升級過程中遇到了一些問題,簡單記錄一下,做個分享。另外,本文中的程序只為示例代碼,並非公司生產環境代碼。

遇到什么問題

從SpringBoot1.x升級到SpringBoot2.x之后,解決完編譯異常,運行程序,在程序啟動時報錯:

報錯信息

報錯信息就已經很直白的告訴了我們錯誤原因:

配置屬性名稱“com_shen”無效

無效字符: '_', 原因:規范名稱應為kebab-case(用'-'分隔),小寫字母數字字符,並且必須以字母開頭

怎么解決

經過排查,是因為在application.properties文件中有如下一個配置項:

com_shen.name=xiaohei

對應Java程序代碼:

@Getter
@Setter
@ConfigurationProperties(prefix = "com_shen")
public class Service {
    private String name;
}

結合報錯日志,我們可以很容易的解決這個問題,去掉配置項中的_,將配置項name修改為com.shen.name即可。

源碼解析

你以為文章寫到這里就結束了嗎?其實並沒有。hhhhhh,通過這個問題,我們來看一下SpringBoot2.x的內部源碼。什么,你不知道該從哪里入手來看這個源碼,沒關系,我們一步一步來。

點開@ConfigurationProperties源碼,

@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 : https://spring.io/blog/2018/03/28/property-binding-in-spring-boot-2-0


歡迎關注公眾號,大家一起學習成長。

Coder小黑


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM