從args講到springboot全套配置體系架構(二)

回顧

在上文中講到了系統的環境變量和屬性,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

當然現實開發中還是不要做如此愚蠢得事情。

發佈了119 篇原創文章 · 獲贊 28 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章