回顧
在上文中講到了系統的環境變量和屬性,system.env和system.properties.這是java的兩個全局變量。也就是說在java的應用程序中,你在任何爲止都能取到其中的值。
並且我們可以通過set方法將(k,v)放到這兩個全局變量中。
並且我們也知道了配置文件幾乎可以從任何地方來,任何方式來,具體看自己的需求是什麼樣了。
那我們現在來看看spring 是不是將配置放到了這兩個變量中呢?
二、Spring框架如何讀取配置文件?
我們先來看一段程序
@Autowired
Environment environment;
@Test
public void contextLoads() {
System.out.println(System.getProperty("redis.host"));
System.out.println(System.getenv("redis.host"));
System.out.println(environment.getProperty("redis.host"));
}
控制檯輸出結果
null
null
127.0.0.1
我們發現spring加載的配置文件並不會存到 System下的兩個全局變量中,而是存到了一個 Environment 實例中。
那我們來看看 這個 Environment 是何方神聖,啓動時加載默認配置以及系統配置。
Environment接口
Environment 這個接口可以說是貫穿了spring得全套源碼體系。它繼承了 PropertyResolver 所有加載得配置文件均在這個接口中。
包括System.getenv 和 System.getProperty 這兩個全局變量也可以從這個接口中讀取到。我們來實驗下
@Autowired
Environment environment;
@Test
public void contextLoads() {
System.out.println(System.getProperty("redis.host"));
System.out.println(System.getenv("redis.host"));
System.out.println(environment.getProperty("redis.host"));
System.out.println(environment.getProperty("USERNAME"));
}
控制檯輸出
null
null
127.0.0.1
yaozhongjie
可以看到 USERNAME 這個是系統得變量,我們獲取到了。
也就是說 spring得整個框架屬性配置是圍繞着 Environment 得接口來得。
我們打印了注入得類名發現實例化得是這個StandardEnvironment
下面是類圖
項目啓動時,先往把systemEnvironment 和systemProperties 放進了這個實例。當然還有 application 和 bootstrap 默認配置文件。
而自定義得配置文件是通過 Configuration註解或Component 註解
+propertySource 註解在bean初始化前後 進行加載得
AbstractApplicationContext.refresh() 方法中得invokeBeanFactoryPostProcessors(beanFactory);這一步進行初始化得。但是這個接口只提供了 取屬性得方法,並未提供設置屬性得方法哦。
StandardEnvironment類
@Autowired
Environment environment;
@Autowired
StandardEnvironment standardEnvironment;
@Test
public void contextLoads() {
System.out.println(System.getProperty("redis.host"));
System.out.println(System.getenv("redis.host"));
System.out.println(environment.getProperty("redis.host"));
System.out.println(environment.getProperty("USERNAME"));
System.out.println(environment.getClass());
System.out.println(environment);
MutablePropertySources propertySources = standardEnvironment.getPropertySources();
propertySources.forEach(System.out::println);
}
控制檯打印
null
null
127.0.0.1
yaozhongjie
class org.springframework.core.env.StandardEnvironment
StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, MapPropertySource {name='Inlined Test Properties'}, PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}, ResourcePropertySource {name='class path resource [redis.properties]'}]}
ConfigurationPropertySourcesPropertySource {name='configurationProperties'}
MapPropertySource {name='Inlined Test Properties'}
PropertiesPropertySource {name='systemProperties'}
OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}
RandomValuePropertySource {name='random'}
OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}
ResourcePropertySource {name='class path resource [redis.properties]'}
可以到這個實際上存儲得是不同類型得文件對象。
ResourcePropertySource 爲資源類型
OriginTrackedMapPropertySource 應用原始配置
那麼這個時候問題來了,我如果寫了兩個一樣得key,放在不同得配置文件下。那麼用environment 中會讀出哪個呢?
新建個 mq.properties
redis.host=123123123
redis.password=mq
新建配置類如下
@Configuration
@PropertySource(value = "classpath:mq.properties")
@ConfigurationProperties(prefix = "redis")
@Data
public class MqConfig {
private String host;
private String password;
private int port;
}
測試類中打印
@Autowired
MqConfig mqConfig;
@Autowired
RedisConfig redisConfig;
@Test
public void contextLoads() {
System.out.println(redisConfig.getHost());
System.out.println(mqConfig.getHost());
}
控制檯輸出
127.0.0.1
127.0.0.1
發現mqConfig 取到得也是redis.properties 中得值,那麼我們怎麼取到mq.properties中得值呢?
代碼如下
MutablePropertySources propertySources = standardEnvironment.getPropertySources();
String property = (String) propertySources.get("class path resource [mq.properties]").getProperty("redis.host");
System.out.println(property);
控制檯輸出這樣子就取到了。
123123123
當然現實開發中還是不要做如此愚蠢得事情。