情景描述
最近新搭建了一個項目,從Spring遷到了Springboot,為了兼容Spring加載配置文件的風格,所以還想把PropertyPlaceholderConfigurer放在.xml文件里面,然后通過@importSource來加載.xml文件將配置加載到spring環境中,通過@value或者PropertyUtil來引入對應配置的值。於是發現了以下問題,並根據這些問題進行了問題拓展。
問題描述
1.在.xml引入PropertyPlaceholderConfigurer時,若項目中存在@PropertySource注解,@ConfigurationProperties可以正常加載PropertySource中的配置(啟動時發現Bean正常),但是@Value會在啟動時報錯解析不了占位符;若@ConfigurationProperties加載的是.xml中配置文件的值,則也為空。
2.在使用PropertyUtil(由.xml加載配置)時發現,在通過.xml加載配置的這個方法上,public static 變量在@Configuration的配置類通過PropertyUtil獲取配置值時PropertyUtil還未加載(值為null),在其他@Component(包括@Controller)中是可以正常獲取到值(說明已經加載)。
解決方案&原理分析
問題1:
其中@PropertySource注解管理的所有配置文件相當於一個PropertyPlaceholderConfigurer,只不過是Springboot自己管理的,而.xml中的PropertyPlaceholderConfigurer又是一個,這就會出現多個PropertyPlaceholderConfigurer的問題(目測是由於先加載了@ImportSource中.xml的PropertyPlaceholderConfigurer導致該問題),多PropertyPlaceholderConfigurer問題原因如下:
在spring bean裝配時,一個PropertyPlaceholderConfigurer就是一個后置處理器BeanFactoryPostProcessor。在裝配完PropertyPlaceholderConfigurer之后,就會觸發org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor>, ConfigurableListableBeanFactory)方法,代碼如下:
/** * Invoke the given BeanFactoryPostProcessor beans. */ private void invokeBeanFactoryPostProcessors( Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); } }
在每調用完一個BeanFactoryPostProcessor之后,就會去解析所有的bean中引用properties的占位符,這時就會出現占位符不能解析的問題(不能解析的占位在后面的BeanFactoryPostProcessor中,也就是PropertyPlaceholderConfigurer實例)。
而在使用@Value時,由於使用了占位符,而.xml中的PropertyPlaceholderConfigurer先加載解析占位符但是該配置未存在,所以會報錯占位符解析失敗。
而使用@ConfigurationProperties時,並沒有使用占位符,所以如果是在@PropertySource中的配置可以正常加載
但是我個人理解@ConfigurationProperties加載配置是用的@PropertySource的PropertyPlaceholderConfigurer,所以如果配置不是用@PropertySource加載,則加載結果為null(建議配套使用)
解決方法:
<property name="ignoreUnresolvablePlaceholders" value="true"/>
加上上面的一行,表示可以忽略未解析到的占位符。這樣就不會報錯。
問題2:
附:
@PropertySource API:Resource location wildcards (e.g. **/*.properties) are not permitted; each location must evaluate to exactly one .properties resource.(不允許使用資源位置通配符(例如** / *.屬性);每個位置必須只評估一個.properties資源)
如果對我上面的分析存在異議歡迎討論啊,希望相互提高。
轉載請注明:https://www.cnblogs.com/fnlingnzb-learner/p/11067338.html