apollo作為應用配置管理中心框架,可以將應用中的配置信息集中管理,且在apollo中修改配置值之后應用中可以動態更新。
動態刷新的原理:應用中配置了apollo后,在spring容器啟動過程中,apollo將屬性中含有@Value注解與${}的bean注冊到apollo框架定義的注冊表中。然后通過http長輪詢不停地去獲取apollo服務端的配置信息,一旦配置發生變化,apollo會根據配置的key找到注冊的bean,然后修改bean的屬性,從而實現了配置動態生效。
配置值動態刷新的情況有下面幾種:1 通過@Value注解讀取配置值;2 通過@ConfigurationProperties注解讀取配置。
(一) @Value 可以添加在method(比如setxxx())、field(屬性)、parameter。apollo中的配置修改后,應用中會動態刷新。
1)讀取簡單類型:java基本類型、string等。@Value("${xxx:defaultvalue}")
2)讀取list、map、set等,或將一定格式的string轉為collection:
/** * map配置 */ @Value("#{${system.defaultModule}}") private Map<String,String> defaultModule; /** * 簡單字符串 */ @Value("${system.version: v1.0}") private String version; /** * 將字符串轉為集合 */ @Value("#{'${system.products}'.split(',')}") private List<String> list; // set<string>, string[]均可 @Value("${system.products}") private void setProducts(String productStr){ products = productStr.split(","); }
apollo配置如下
system.defaultModule: {"a":"10", "b":"100"} system.products: aaa,44,678 system.version: v3.0
(二)@ConfigurationProperties 讀取配置生成bean。
apollo中的配置修改后,應用中不會動態刷新,需要手動編寫程序實現動態刷新。因為spring啟動時,已讀取配置值且生成了對象。之后再修改配置值后,對象中的屬性值並不會改變。
(三)數據庫連接配置更改后,對已創建連接不會刷新,只對新生成連接對象生效。
(四)針對bean屬性值無法動態刷新的問題,有以下幾種方法可以實現動態刷新。
1)基於RefreshScope結合@ApolloConfigChangeListener實現
2)基於EnvironmentChangeEvent結合@ApolloConfigChangeListener實現
3)示例代碼如下
properties配置
@ConfigurationProperties(prefix = "wcc.system") @RefreshScope @Component("testApolloConfigProperties") @Data @AllArgsConstructor @NoArgsConstructor @Builder @ToString public class TestApolloConfigProperties { private Map<String,String> defaultModule; private List<String> products; private String version; }
listener方式一
@Component public class TestApolloRefreshScopeListener { @Autowired private RefreshScope refreshScope; @ApolloConfigChangeListener(interestedKeyPrefixes = "wcc.system") public void refresh() { // 指定要刷新的bean refreshScope.refresh("testApolloConfigProperties"); } }
listener方式二
@Component public class TestApolloEnvironmentChangeEventListener { @Autowired private ApplicationContext applicationContext; @ApolloConfigChangeListener(interestedKeyPrefixes = "wcc.system") public void doRefresh(ConfigChangeEvent changeEvent){ applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys())); } }