因为Spring Cloud Config需要配置一些东西才能热加载配置,而且没有图形界面,也没有灰度发布,诸多原因再加上Apollo开源了,所以很多公司还是比较青睐Apollo,所以今天花了半天时间研究了一下,试了一下本地模式,感觉还是挺不错的,废话不多说了。官网传送门
当前最新版本为Apollo 1.6.1-Release,老规矩找个喜欢的文件夹clone。
// clone source code
git clone https://github.com/ctripcorp/apollo.git
// compile source code
cd apollo/
mvn install -Dmaven.test.skip=true
mvn idea:idea
或
mvn eclipse:eclipse
想让Apollo跑起来需要配置最基础的3个模块,config、admin、portal,配置数据库信息和apollo-meta,我是用的本地MySQL 5.7。
在script下面的sql文件夹有两个sql文件,分别是config和portal需要用到的表,直接打开客户端运行脚本就可以了,不用多做介绍,执行完之后准备下一步,修改配置文件。
# application.yml
datasource:
url: jdbc:mysql://localhost:3306/apolloconfigdb?characterEncoding=utf8
username: root
password: 888888
# apollo-env.properties因为我只配置了dev,所以把其他的注释掉了
local.meta=http://localhost:8080
dev.meta=http://localhost:8080
#dev.meta=${dev_meta}
#fat.meta=${fat_meta}
#uat.meta=${uat_meta}
#lpt.meta=${lpt_meta}
#pro.meta=${pro_meta}
config -> admin -> portal
,启动完成之后就可以通过localhost:8070访问Apollo控制台了。源码中有demo部分,但不是我们常用的形式,所以就不以源码demo说了,我们IDEA创建一个最最最基础的Spring Boot project,添加上spring-boot-starter-web,和apollo-client,比较直观。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.ctrip.framework.apollogroupId>
<artifactId>apollo-clientartifactId>
<version>1.6.0version>
dependency>
application.yml
配置,注意application-name和app-id,要与apollo保持一致。虽然application-name不一致也不影响,但是还是建议统一一下比较好。因为Apollo使用了8080,所以我这里改成8888。server:
port: 8888
spring:
application:
name: ddd-demo
apollo:
bootstrap:
eagerLoad:
enabled: true
enabled: true
namespaces: application
meta: http://localhost:8080
app:
id: ddd
配置文件中的namespaces与下图对应,可以添加多个以英文逗号隔开。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import lombok.Data;
@Data
@Configuration
public class TestApolloConfig {
@Value("${apollo}")
private String apollo;
}
@RestController
@RequestMapping("apollo")
public class ApolloController {
@Value("${apollo}")
private String apollo;
@Resource
private TestApolloConfig testApolloConfig;
@GetMapping("test")
public String test() {
String apollo1 = testApolloConfig.getApollo();
return "TestApolloConfig:" + apollo1 + ";@Value:" + this.apollo;
}
}
http://localhost:8888/apollo/test
修改配置项 -> 保存 -> 重新发布
http://localhost:8888/apollo/test
,成功。最简单的实践完成了,看了一下客户端更新配置的源码,远程获取配置的核心类RemoteConfigRepository
,在构造的时候启动了schedulePeriodicRefresh
,周期性获取,默认间隔实践是2s,在ConfigUtil
中默认。
private long longPollingInitialDelayInMills = 2000;//2 seconds
后面专门再写一篇博客简单分析一下原理,Apollo配置动态加载的核心思路还是比较清晰的。
// 构造时初始化了一堆东西
public RemoteConfigRepository(String namespace) {
m_namespace = namespace;
m_configCache = new AtomicReference<>();
m_configUtil = ApolloInjector.getInstance(ConfigUtil.class);
m_httpUtil = ApolloInjector.getInstance(HttpUtil.class);
m_serviceLocator = ApolloInjector.getInstance(ConfigServiceLocator.class);
remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class);
m_longPollServiceDto = new AtomicReference<>();
m_remoteMessages = new AtomicReference<>();
m_loadConfigRateLimiter = RateLimiter.create(m_configUtil.getLoadConfigQPS());
m_configNeedForceRefresh = new AtomicBoolean(true);
m_loadConfigFailSchedulePolicy = new ExponentialSchedulePolicy(m_configUtil.getOnErrorRetryInterval(),
m_configUtil.getOnErrorRetryInterval() * 8);
gson = new Gson();
this.trySync();
this.schedulePeriodicRefresh();
this.scheduleLongPollingRefresh();
}