背景
工作中負責的一套計費系統需要開發一個新通知功能,在扣費等事件觸發后發送MQ,然后消費MQ發送郵件或短信通知給客戶。因為有多套環境,測試時需要知道是從哪套環境發出的郵件,又不想維護多套通知模板,因此就打算在各環境的properties中聲明不同的title前綴,實現類似[DEV]您的xx月賬單、[TEST]您的xx月賬單的效果,但是這個前綴需要在生產環境中去掉,因此我想到用Spring @Value的默認值來實現,偽代碼如下:
@Value("${notice.mail.titlePrefix:}")
private String mailTitlePrefix;
public void doSendEmail() {
...
String title = "xxx";
if (StringUtils.isNotBlank(mailTitlePrefix)) {
title = mailTitlePrefix + title;
}
mailSender.send(title, content, recevier);
}
采用上述代碼后,運行發現,即使在properties中配置了值,但是mailTitlePrefix一直是空字符串"",一旦把冒號去掉又能正常讀取到配置的值,修改:后面的數據為其他值,如@Value("${notice.mail.titlePrefix:113}") ,mailTitlePrefix的值也為113,即@Value一直只能獲取到默認值。
工程采用spring標簽聲明了兩個property-placeholder,分別讀取不同的配置文件:
<context:property-placeholder order="0" location="classpath*:db.properties" ignore-unresolvable="true"/>
<context:property-placeholder order="0" location="classpath*:config.properties" ignore-unresolvable="true"/>
notice.mail.titlePrefix的配置在config.properties文件中。
問題定位
可以確定是spring屬性值注入出現的問題,google一番后,找到一篇相同問題的文章spring-boot-spring-always-assigns-default-value-to-property-despite-of-it-bein。
按照 SPR-9989 上的說明,Spring在有多個property-placeholder時,如果第一個property-placeholder在處理@Value時沒有找到屬性值,則會采用默認值對屬性進行賦值,然后第二個property-placeholder就會忽略該@Value,於是@Value獲取到的永遠都是默認值。
問題解決
合並property-placeholder聲明:
<context:property-placeholder order="0" location="classpath*:db.properties,classpath*:config.properties" ignore-unresolvable="true"/>
追加
這個bug一直是未修復狀態,好像Spring官方不認為這是一個bug?截至spring 5.2.x版本也有這個問題。完整的TestCase詳見larva-zhang/some-problems-record/spring-always-assigns-default-value-to-Value-annotation
