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())); } }