前言
在朋友的專案有個自定義組態檔user.yml,其內容如下
user:
userId: 1
name: 張三
email: [email protected]
其映射物體內容為如下
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@PropertySource(value = "https://www.cnblogs.com/linyb-geek/p/user.yml",encoding = "utf-8",factory = CustomYmlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "user")
@Configuration
public class User {
private String name;
private Long userId;
private String email;
}
專案啟動后,輸出的user內容為
User(name=Administrator, userId=1, [email protected])
很明顯name的內容不是我們想要的
排查
從跟蹤的原始碼可以發現有個systemProperties配置排在user.yml前面,systemProperties這是個啥東西,見名之意,這明顯就是系統屬性配置,而systemProperties里面又有啥內容,我們繼續跟蹤下
從原始碼可以看出systemProperties里面有個key為user.name,value為Administrator,
從這邊我們可以看出我們控制臺列印出來的內容其實是systemProperties的內容,由此我們可以推斷出當系統變數和自定義配置變數都有一樣的key時,將以系統變數的值為準,
看到這邊也許有朋友說你這是在胡說八道,就憑這個現象就得出這個結論,那好為了證明這個結論,我們不得繼續斷點排查下去,不過在斷點之前,我們去spring官網溜溜,看有沒有啥識訓,進官網我們可以看到有這么一段話
這段話的意思是默認情況下,系統屬性優先于環境變數, 因此,如果在呼叫env.getProperty(“ my-property”)的程序中在兩個地方都同時設定了my-property屬性,則系統屬性值“ wins”并回傳, 請注意,屬性值不會合并,而是會被前面的條目完全覆寫,
看吧,官網它自己也這么說
如果我們想要自定義的屬性優于系統屬性,要怎么做
這段也是從官網截圖來的,其意思是整個機制是可配置的, 也許您具有要集成到此搜索中的自定義屬性源, 為此,實作并實體化您自己的PropertySource并將其添加到當前環境的PropertySources集中
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());
這個是官方解法,
我這邊在提供2種解法,
- bean初始化之前,修改屬性檔案加載順序
- 在bean初始化后,變更bean的屬性值
其實作代碼如下
ntBeanFactoryPostProcesser implements BeanFactoryPostProcessor, ApplicationContextAware, BeanPostProcessor {
private ApplicationContext applicationContext;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//方法三:在bean初始化后,變更bean的屬性值
// if("user".equals(beanName)){
// User user = (User)bean;
// System.out.println("----------------before---------------------");
// System.out.println("user-->"+user);
// System.out.println("----------------after---------------------");
// String propertySourceName = "user.yml";
// PropertySource propertySource = getPropertySource(propertySourceName);
// if(!ObjectUtils.isEmpty(propertySource)){
// user.setName(String.valueOf(propertySource.getProperty("user.name")));
// }
// System.out.println("user-->"+user);
//
// }
return bean;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
printPropertySourceNames();
String propertySourceName = "user.yml";
PropertySource propertySource = getPropertySource(propertySourceName);
if(!ObjectUtils.isEmpty(propertySource)){
//方法一 bean初始化之前,修改屬性檔案加載順序
getEnvironment().getPropertySources().remove(propertySourceName);
getEnvironment().getPropertySources().addFirst(propertySource);
}
// 方法二 新增一個PropertySource,并把他的加載順序置為第一位
// Map<String, Object> propertiesSource = new HashMap<>();
// propertiesSource.put("user.name", "張三");
// PropertySource newPropertySource = new MapPropertySource("newPropertySource", propertiesSource);
// getEnvironment().getPropertySources().addFirst(newPropertySource);
}
private PropertySource getPropertySource(String propertySourceName){
return getEnvironment().getPropertySources().get(propertySourceName);
}
private AbstractEnvironment getEnvironment(){
return (AbstractEnvironment)applicationContext.getEnvironment();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private void printPropertySourceNames(){
getEnvironment().getPropertySources().stream().forEach(p-> System.out.println(p.getName()));
}
}
改完后,我們看下控制臺此時輸出的內容為
User(name=張三, userId=1, [email protected])
總結
其實要想自定義檔案屬性值不和系統變數的值產生沖突,最快捷的方法,就是讓自定義檔案屬性的key和系統變數的key不一樣就好,能少寫代碼就盡量少寫
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/136609.html
標籤:Java
上一篇:【JAVA :File類的用法(一)】File類的構造方法-File類創建檔案與檔案夾
下一篇:java_資料型別轉換、運算子
