配置管理中心(Apollo)
1. 应用场景
- 去除配置文件,隐藏配置信息,配置集中管理
- 自动根据部署环境切换配置 (如:数据库、中间件、SDK请求参数)
- 代码逻辑切换的开关(如:某些测试的代码切换、活动等临时功能的开关)
- 手动触发的代码逻辑(如:刷新缓存)
- 页面展示动态内容(如:导航、广告、活动)
- 进阶应用场景 (如:动态切换数据库、调整日志级别)
2. 适用环境
- 部署环境:公司内网物理机、PAAS
- 开发语言:Java(spring、springboot)、.Net、Go、Python、NodeJS、PHP
java以外语言的使用方法详见Apollo官方文档
3. Apollo
适应多种情况的配置方案
项目(project) -> 环境(env) -> 集群(cluster) -> 命名空间(namespace) -> 配置项(property)
命名空间分私有/公有,私有的只有匹配的AppId的才能读取,公有的允许其他项目中读取
命名空间可以通过继承公共命名空间来复用配置配置实时生效 配置的变动都会主动推送到所有引用的客户端
权限管理 项目查看、配置项的编辑和发布都有相应的权限控制,并且所有操作都有日志记录
配置版本管理 配置项都会记录历史修改的版本,可以随时进行回滚
灰度测试 允许进行灰度发布,针对特定的客户端进行配置项的更新
客户端监控 每个命名空间都可以查看引用的客户端信息
3.1 新建配置项目
- Apollo地址
http://apollo-portal-dev-zqt-middleware-be.app.eazytec.intra/signin
apollo admin
- 新建项目
选择对应部门
保证appId唯一
- 新建配置项
注意选择对应的环境DEV/PRO
- 编译properties文件
只会修改选择的环境的配置
yml & properties转换
- 同步DEV/PRO的配置
- 发布配置
只有已发布的配置项才会更新
DEV和PRO需要单独发布
- 创建命名空间
关联公共namespace : 选择从公共命名空间继承配置项
- 创建灰度版本
选择用来测试的引用客户端,修改配置项,发布后测试
全量发布则所有修改替换主版本
放弃则删除灰度版本
4. Java集成
- pom引入依赖包
<!--guava 19.0-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>com.eazytec.middleware</groupId>
<artifactId>apollo-support</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 配置AppId 与apollo项目的appId相同
启动参数
-Dapp.id=YOUR-APP-IDclasspath:/META-INF/app.properties
#apollo app.id=ufs-provider #cat app.name=ufs-provider
- 环境切换 现支持环境DEV 与 PRO,默认为DEV
- 启动参数
-Denv=YOUR-ENVIRONMENT- 环境变量 ENV
- 配置文件
mac/linux : /opt/settings/server.properties
windows : c:\opt\settings\server.properties
env=YOUR-ENVIRONMENT
- api
1.获取项目私有命名空间配置
//获取项目app-id对应的项目的默认命名空间(application)
Config config = ConfigService.getAppConfig();
String someKey = "def.key";
String someDefaultValue = "def.value";
String value = config.getProperty(someKey, someDefaultValue);
2.获取公共命名空间配置
//获取公共命名空间 public.config
Config config = ConfigService.getConfig("public.config");
String someKey = "def.key";
String someDefaultValue = "def.value";
String value = config.getProperty(someKey, someDefaultValue);
3.监听配置变化事件
Config config = ConfigService.getAppConfig();
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
System.out.println("Changes for namespace " + changeEvent.getNamespace());
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
}
}
});
- spring集成
spring版本 3.1.1+
<!--1.加载默认命名空间配置(application) -->
<apollo:config/>
<!--2.加载多个配置,写在前面的命名空间的配置项会覆盖后面的-->
<apollo:config namespaces="TNG.dubb,TNG.druid"/>
<!--3.自定义加载顺序,order小的优先加载,覆盖后面的-->
<apollo:config order="2"/>
<apollo:config namespaces="FXTNG.dubb,TNG.druid" order="1"/>
- spring boot集成
通过@EnableApolloConfig和@Configuration加载配置,完全代替properties和yml
/**1.加载默认命名空间配置(application) **/
@Configuration
@EnableApolloConfig
public class TestConfig1 {
}
/**2.加载多个配置,写在前面的命名空间的配置项会覆盖后面的**/
@Configuration
@EnableApolloConfig({"application","TNG.dubbo", "TNG.druid"})
public class TestConfig2 {
}
/**3.自定义加载顺序,order小的优先加载,覆盖后面的**/
@Configuration
@EnableApolloConfig(order = 2)
public class TestConfig31 {
}
@Configuration
@EnableApolloConfig({"application","TNG.dubbo", "TNG.druid"}, order = 1)
public class TestConfig32 {
}
- spring placeholder
1.XML中注入配置 ${key:defValue}
配置会自动更新
<apollo:config/>
<bean class="TestConfigBean">
<property name="timeout" value="${timeout:100}"/>
<property name="batch" value="${batch:200}"/>
</bean>
2.java中注入配置 @Value
public class TestConfigBean {
@Value("${timeout:100}")
private int timeout;
private int batch;
@Value("${batch:200}")
public void setBatch(int batch) {
this.batch = batch;
}
public int getTimeout() {
return timeout;
}
public int getBatch() {
return batch;
}
}
3.注入整个java bean
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestConfigBean configBean() {
return new TestConfigBean();
}
}
4.通过ConfigurationProperties注入
@ConfigurationProperties(prefix = "redis.cache")
public class SampleRedisConfig {
private int expireSeconds;
private int commandTimeout;
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public void setCommandTimeout(int commandTimeout) {
this.commandTimeout = commandTimeout;
}
}
- Apollo Annotation
1.@ApolloConfig
注入Config对象
2.@ApolloConfigChangeListener
注册ConfigChangeListener
public class TestConfig {
@ApolloConfig
private Config config;
@ApolloConfig("TNG.dubbo")
private Config dubboConfig;
@ApolloConfigChangeListener
private void someOnChange(ConfigChangeEvent changeEvent) {
if (changeEvent.isChanged("batch")) {
batch = config.getIntProperty("batch", 100);
}
}
@ApolloConfigChangeListener({"application", "FX.apollo"})
private void dubboOnChange(ConfigChangeEvent changeEvent) {
//do something
}
}