Spring Boot整合Apollo
因为Spring Cloud Config需要配置一些东西才能热加载配置,而且没有图形界面,也没有灰度发布,诸多原因再加上Apollo开源了,所以很多公司还是比较青睐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
使用IDE打开Apollo
准备工作
想让Apollo跑起来需要配置最基础的3个模块,config、admin、portal,配置数据库信息和apollo-meta,我是用的本地MySQL 5.7。
配置数据库
在script下面的sql文件夹有两个sql文件,分别是config和portal需要用到的表,直接打开客户端运行脚本就可以了,不用多做介绍,执行完之后准备下一步,修改配置文件。
修改配置文件
3个工程的配置文件需要修改加上数据库配置
# 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}
启动Apollo
- 启动服务:修改完配置之后就可以启动Apollo了,按顺序启动服务
config -> admin -> portal
,启动完成之后就可以通过localhost:8070访问Apollo控制台了。
- 创建项目:AppId要唯一,需要配置到客户端,应用名称填写客户端ApplicationName。
- 新增配置:key就是我们用@Value(“key”),所用到的,value就是我们配置值可以添加备注,然后我们默认选择DEV。
- 发布:点击发布按钮即可完成发布
客户端获取配置
源码中有demo部分,但不是我们常用的形式,所以就不以源码demo说了,我们IDEA创建一个最最最基础的Spring Boot project,添加上spring-boot-starter-web,和apollo-client,比较直观。
- 添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.6.0</version>
</dependency>
- 添加application.yml:添加
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与下图对应,可以添加多个以英文逗号隔开。
- 编写配置类:我这边用了两种方式来获取配置,一种是直接在需要的地方@Value,另一种是配置类。
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;
}
- 编写Controller:然后写了一个Controller,方便测试
@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();
}