配置自动刷新
接上篇文章,我们已经将配置文件放到git上进行管理,但是有时候我们需要对配置的内容做一些实时更新,那么接着上篇文章的例子,我们把它改造成可以动态刷新的例子
在改造之前,我们先将eureka
和config-server
都启动起来,
然后将gateway
作为config-client
启动,
并访问gateway
提供的REST API http://localhost:7200/test/get
来获得配置信息,可以看到返回结果为:dev
。
接着,我们修改git仓库中的配置文件gateway-dev.properties
将env=dev
修改为env=dev1
,
再次访问http://localhost:7200/test/get
,发现结果还是:dev
我们看到即使我们改了配置文件,程序还是接口返回的还是之前的配置,说明使用的还是之前的配置,想要使得修改完配置之后,程序加载到最新的配置,那么我们是不是把这些配置文件的在程序中刷新就行了呢?
下面我们在config-client端gateway模块增加一些操作来实现配置的刷新,spring-boot-starter-actuator
是spring提供的监控模块,其中的/refresh
接口就可以实现刷新配置的功能。
- 首先在gateway的
pom.xml
中加入对应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 在我们需要刷新配置的地方加上
@RefreshScope
注解
@RestController
@RequestMapping("test")
@RefreshScope
public class TestController {
@Value("${env}")
private String env;
@RequestMapping("/get")
public String get() {
return env;
}
}
- 重启gateway,访问一次
http://localhost:7200/test/get
,可以看到当前的配置文件的配置 - 修改git仓库中的配置文件
gateway-dev.properties
将env=dev
修改为env
值为dev1
- 再次访问
http://localhost:7200/test/get
,发现配置值还是没变 - 通过POST请求发送到
http://localhost:7200/refresh
,我们看到返回内容如下,代表env
参数的配置内容被更新了
[
"config.client.version",
"env"
]
- 再次访问
http://localhost:7200/test/get
,可以看到配置值已经是更新之后的值了
通过上面的方法,我们发现实际上我们并没有重启我们的gateway
服务,就把我们服务中的配置值替换成了最新的。不重启服务在实际生产中意味着我们不需要重新发版来更新我们的配置。
功能上面是已经实现了,但是总觉得哪里还是有点不够方便。我每次更新完配置之后还要手动的调用一下/refresh
接口,很是麻烦。
能不能在我更新完这些配置之后,不需要手动调用refresh
接口,程序自动刷新呢?
答案是可以的。可以借助git仓库的WebHook功能进行关联,当有Git提交变化时,就给对应的配置主机发送/refresh
请求来实现配置信息的实时更新。
但是,当我们的系统变得非常大之后,微服务越来越多时,维护这样的刷新清单也将成为一个非常大的负担,而且很容易犯错,那么有什么办法可以解决这个复杂度呢?
Spring Cloud Bus
就起到了它的作用,以消息总线的方式进行通知配置信息的变化,完成集群上的自动化更新。
数据库配置
上面介绍了配置中心采用了git的方式进行配置的存储,以及更改配置如何进行自动刷新。下面将介绍另外一种配置的存储方式,这也是spring cloud config
从Edgware
版本开始新增的一种方式:采用数据库存储配置信息
构建配置中心服务端
- 创建一个
spring boot
项目引入下面的依赖
<dependencies>
<!-- 配置中心的基础依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 数据库连接JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
- 创建一个用于存储服务配置的数据表
system_properties
CREATE TABLE `system_properties` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`key` varchar(100) NOT NULL COMMENT '键',
`value` varchar(2000) NOT NULL COMMENT '值',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态,1正常,0停用',
`remarks` varchar(200) NOT NULL DEFAULT '' COMMENT '描述',
`application` varchar(50) NOT NULL COMMENT '各微服务名称 对应spring.application.name',
`profile` varchar(10) NOT NULL DEFAULT 'default' COMMENT '环境,对应spring.profiles.active, default表示适用于所有环境',
`label` varchar(10) NOT NULL DEFAULT 'master' COMMENT '读取的分支,一般为master',
`intime` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_system_properties_key_application_profile` (`key`,`application`,`profile`),
KEY `idx_system_properties_application_profile_label` (`application`,`profile`,`label`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='配置文件配置中心服务读取'
- 配置启动类
@EnableConfigServer
@SpringBootApplication
public class ConfigServersDBApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServersDBApplication.class,args);
}
}
- 添加配置文件
application.propeties
spring.application.name=config-servers-db
server.port=8763
# 必须设置,将配置中心的存储实现切换到jdbc的方式
spring.profiles.active=jdbc
# 非必须,这里由于采用mysql数据源,key、value是保留关键词,原生的实现语句会报错
# 所以需要重写一下这句查询语句(如果存储的表结构设计不同于上面准备的内容,也可以通过这个属性的配置来修改配置的获取逻辑)
spring.cloud.config.server.jdbc.sql=SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?
# 数据库连接信息配置
spring.datasource.url=jdbc:mysql://localhost:3306/config-db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
5.启动配置中心的服务,然后按照格式/${application}/${profile}/${label}
该路径,就可以获取到对应的微服务应用配置。
"name": "application",
"profiles": [
"default"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "application-default",
"source": {
"env": "dev",
}
}
]
- 至于客户端如何获取这些配置,和放在git中存储没有什么区别,这里就不再赘述了,可以参考上面的,或者上一篇文章分布式配置中心的使用。当然,我们把配置存放在数据库中,自然可以结合前端页面的增删改查,对配置信息进行更改,然后进行配置的刷新。