Apollo(阿波罗)是一款可靠的分布式配置管理中心,诞生于携程框架研发部,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
服务端基于 Spring Boot 和 Spring Cloud 开发,打包后可以直接运行,不需要额外安装 Tomcat 等应用容器。
Java 客户端不依赖任何框架,能够运行于所有 Java 运行时环境,同时对 Spring / Spring Boot 环境也有较好的支持。
更多产品介绍请查看官方文档:https://www.apolloconfig.com/
Apollo Client 支持开箱即用,Spring Boot 应用不需要做任何改动。2.0.0及以上版本支持Java 17。
1)在你的 Spring Boot 项目中添加依赖配置:
<!-- Apollo Client >=2.0.0 -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.0.1</version>
</dependency>
2)添加配置参数(以下是推荐配置):
## Apollo Configuration
# 多环境时,需要通过启动参数来指定配置环境:-Denv=DEV
app.id=YOUR-APP-ID
apollo.bootstrap.enabled=true
apollo.bootstrap.eagerLoad.enabled=true
apollo.bootstrap.namespaces=application
apollo.meta=http://config-service-url
apollo.cache-dir=./config-cache
apollo.cluster=default
简单两步,就可以快速地将 Spring Boot 项目的配置参数迁移到 Apollo 配置中心,代码不需要做任何改动。
当你在 Spring Boot 中使用
@ConfigurationProperties
注解配置参数时,Apollo Client 无法自动更新。需要在项目中增加些配置才能解决这个问题。
1)添加 Maven 依赖,该依赖包属于 Spring Cloud 项目。
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
2)增加配置监听器:@ApolloConfigChangeListener
注解默认只能自动更新 application
命名空间的配置属性,其他命名空间的配置属性更新可参考下列配置:
@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "apollo.bootstrap.enabled", havingValue = "true")
public class ApolloCofinguration implements ApplicationContextAware, ConfigChangeListener {
private static ApplicationContext applicationContext = null;
protected static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
ApolloCofinguration.applicationContext = applicationContext;
}
/**
* 动态更新配置的通用方法,变更信息将在日志文件中打印日志记录。
*/
protected static void refreshConfigChange(ConfigChangeEvent configChangeEvent) {
configChangeEvent.changedKeys().forEach(key ->
log.info("Apollo ConfigChangeEvent - {}", configChangeEvent.getChange(key))
);
getApplicationContext().publishEvent(new EnvironmentChangeEvent(configChangeEvent.changedKeys()));
}
/**
* 默认只能自动更新 `application` 命名空间的配置属性。
*/
@Override
@ApolloConfigChangeListener({"application", "someNamespace", "anotherNamespace"})
public void onChange(ConfigChangeEvent configChangeEvent) {
refreshConfigChange(configChangeEvent);
}
}
Apollo Client 支持通过启动参数和 Spring Boot application.properties / bootstrap.properties 属性文件配置。
以下是 Apollo Client配置参数的详细说明,查看官方文档可了解更多参数配置信息:https://www.apolloconfig.com/#/zh/usage/java-sdk-user-guide
# [必选] 开启 Apollo 配置
# [注意] 如果配置中使用了 @EnableApolloConfig 注解,该配置将不会生效。
apollo.bootstrap.enabled=true
# [必选] 指定 app.id
# AppId 是应用的身份信息,是从服务端获取配置的一个重要信息。
# 启动参数:-Dapp.id=YOUR-APP-ID
# 系统参数:APP_ID=YOUR-APP-ID
app.id=YOUR-APP-ID
# [必选] 指定配置服务器地址
# 为了实现 meta server 的高可用,推荐通过 SLB 做动态负载均衡。
# 启动参数:-Dapollo.meta=http://config-service-url
# 系统参数:APOLLO_META=http://config-service-url
# 如果是在运行 JAR 文件中指定,需要注意格式是:java -Dapollo.meta=http://config-service-url -jar xxx.jar
apollo.meta=http://config-service-url
# [可选] 指定配置环境
# 启动参数:-Denv=DEV
# 系统参数:ENV=DEV
# 多环境时,该参数必须通过启动参数或系统参数来指定。
# 如果是运行 JAR 文件,需要注意格式是:java -Denv=DEV -jar xxx.jar
# [可选] 指定集群环境
# Apollo 支持配置按照集群划分,也就是说对于一个 AppId 和一个环境,对不同的集群可以有不同的配置。
# 如果还是没找到指定集群,会从默认的集群(default)加载。
# 启动参数:-Dapollo.cluster=SomeCluster
apollo.cluster=default
# [可选] 设置内存中的配置项是否保持和页面上的顺序一致,默认值:false
# 有些场景会强依赖配置项的顺序(如 Spring Cloud Zuul 的路由规则)
# 针对这种情况,可以开启 OrderedProperties 特性来使得内存中的配置顺序和页面上看到的一致。
# -Dapollo.property.order.enable=true
# apollo.property.order.enable=false
# [可选] 将 Apollo 配置加载提到初始化日志系统之前,不过这会导致 Apollo 的启动过程无法通过日志的方式输出。
apollo.bootstrap.eagerLoad.enabled=true
# [可选] 自定义缓存路径
# 启动参数:-Dapollo.cache-dir=/opt/data/config-cache
# 系统参数:APOLLO_CACHE_DIR=/opt/data/config-cache
apollo.cache-dir=/opt/data/config-cache
# [可选] 配置访问密钥(如果配置中心要求使用访问密钥,则必须配置)
# 启动参数:-Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a5
# 系统参数:APOLLO_ACCESS_KEY_SECRET=1cf998c4e2ad4704b45a98a5
# 如果是运行 JAR 文件,需要注意格式是:java -Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a5 -jar xxx.jar
# apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719
# [必选] 指定加载的命名空间,默认会加载 application
apollo.bootstrap.namespaces=application,FX.apollo,application.yml
Environment 可以通过以下3种方式的任意一个配置
1)通过 Java System Property (推荐)
可以通过 Java 的 System Property env 来指定环境。
2)通过操作系统的 System Environment
3)通过配置文件
最后一个推荐的方式是通过配置文件来指定 env=YOUR-ENVIRONMENT
Apollo 客户端会把从服务端获取到的配置在本地文件系统缓存一份,用于在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置,不影响应用正常运行。
本地缓存路径默认位于以下路径,所以请确保 /opt/data 或 C:\opt\data\ 目录存在,且应用有读写权限。
或者,指定配置文件路径(推荐):
apollo.cache-dir=./config-cache
本地配置文件会以下面的文件名格式放置于本地缓存路径下:
{appId}+{cluster}+{namespace}.properties
Spring 应用通常会使用 Placeholder 来注入配置,使用格式如 ${someKey:someDefaultValue}
。冒号前面的是 key,冒号后面的是默认值。
建议在实际使用时尽量给出默认值,以免由于 key 没有定义导致运行时错误。
从 Apollo v0.10.0 开始的版本支持 Placeholder 在运行时自动更新。
1)假设有一个 TestJavaConfigBean,通过 Java Config 的方式可以使用 @Value
的方式注入:
public class TestJavaConfigBean {
@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;
}
}
在 Configuration 类中按照下面的方式使用(假设应用默认的 application namespace 中有 timeout 和 batch 的配置项):
@Configuration
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
2)Spring Boot 提供了 @ConfigurationProperties
把配置注入到 bean 对象中。
Apollo Client 暂不支持配置属性自动更新,所以需要查看前文的自定义配置,解决该问题。(如果不处理,则需要重启应用来更新。)
Apollo 也支持这种方式,下面的例子会把 redis.cache.expireSeconds 和 redis.cache.commandTimeout 分别注入到 SampleRedisConfig 的 expireSeconds 和 commandTimeout 字段中。
@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;
}
}
在 Configuration 类中按照下面的方式使用(假设应用默认的 application namespace 中有 redis.cache.expireSeconds 和 redis.cache.commandTimeout 的配置项):
@Configuration
public class AppConfig {
@Bean
public SampleRedisConfig sampleRedisConfig() {
return new SampleRedisConfig();
}
}
Apollo 配置中心确实给应用开发和管理带来了极大的便利,不再需要因变更某个配置,重新打包、部署和重启应用。类似配置中心的产品还有Nocos、Spring Cloud config,对于企业级应用来讲,Apollo 就已经完全够用了。