1 缘起
本文接着上一篇文章:实践讲解Spring配置中心confighttps://blog.csdn.net/Xin_101/article/details/127584130,实现配置中心文件刷新后自动同步到其他服务,
保证了连接到配置中心的服务实时获取最新的配置文件,
同样,以图文的方式讲解工程实现,
实现原理会在后续的文章中讲解。
2 架构
Spring配置中心Config自动同步配置文件的架构及实现流程架构如下图所示,
由图可知,Spring配置中心Config使用总线的方式,将变更的消息同步到消息队列Q,
分发到其他服务监听消息队列(Q1,Q2,…,Qn),
其他服务将消息加载到各自的内存中。
连接到配置中心的其他服务,会在各自的服务中创建并监听对应的队列(Q1,Q2,…,Qn),
这样,其他服务的数据会同步更新。
服务启动后,注册中心监控面板如下图所示,
由图可知,有两个服务:CONFIG和COMMON两个服务注册到Eureka,
其中,CONFIG为Spring配置中心,COMMON为测试的服务。
Spring配置中心和测试的一个服务启动后,会各自创建并监听对应的队列,
RabbitMQ的监控的队列如下图所示,
由图可知,Spring配置中心监听的队列:springCloudBus.anonymous.2s6VCOyFS2iH-KlGKKaz6g
其他服务监听的队列:springCloudBus.anonymous.ZfL2pRe2Q6WWZSoUK5V7mg
3 配置中心SpringConfig
自动同步配置文件变更,需要引入总线组件,Spring提供的总线组件:bus-amqp,
很好地解决了配置中心数据变更分发的问题,
连接到SpringConfig的服务可以同步自动获取变更的内容。
3.1 依赖
新引入的依赖有bus-amqp和actuator,
bus-amqp用于消息传递,actuator用于URL监听,触发消息同步。
<!-- 服务注册和发现、客户端负载均衡、熔断 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 总线amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3.2 配置参数
配置参数中有两点变更,配置如下:
(1)使用本地路径存储配置文件,用于测试文件变更(替换resources,这里服务启动后无法变更);
(2)暴露触发数据更新的URI,用于触发数据传递(通过队列)。
spring:
application:
name: config
profiles:
active: native
cloud:
config:
server:
native:
search-locations: file:D:/JProject/spring-config-file
rabbitmq:
host: localhost
port: 5672
username: xindaqi
password: 123456
publisher-confirm-type: correlated
publisher-returns: true
virtualHost: /tutorial
listener:
direct:
acknowledge-mode: manual
simple:
acknowledge-mode: manual
concurrency: 1
max-concurrency: 1
retry:
enabled: true
server:
port: 9002
servlet:
session:
timeout: PT10S
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8001/eureka/eureka
management: # 暴露监控路径
endpoints:
web:
exposure:
include: bus-refresh
3.3 共用的配置文件
共用的配置文件:D:/JProject/spring-config-file/application-dev.yml,
其中,my.config用于测试文件内容变更。
spring:
devtools:
restart:
enabled: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_monkey_run?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 10
max-active: 100
min-idle: 10
max-wait: 6000
filters: stat, wall
stat-view-servlet:
enabled: true
login-username: admin
login-password: 123456
logging:
level:
root: DEBUG
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
my:
config: xiaohuahua
3.4 启动
注意使用@EnableConfigServer开启配置中心。
package com.monkey.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* 启动类.
*
* @author xindaqi
* @date 2021-04-30 18:22
*/
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
private static final Logger logger = LoggerFactory.getLogger(ConfigApplication.class);
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
logger.info(">>>>>>>>Config启动成功");
}
}
启动服务时,会监听队列,日志信息如下图所示。
3.5 修改共用文件内容
初始文件内容:
my:
config: xiaohuahua
变更后的内容:
my:
config: xiaolanlan
3.6 刷新参数
通过刷新接口,将最新数据同步到队列,并触发数据同步。
测试结果如下图所示,
这里,没有响应体,只有响应码:204。
刷新数据时,RabbitMQ中的数据监控如下图所示,
虽然没有在队列中看到数据,但是,通过消息速率,
可知,确实是有数据经过该队列的。
4 其他服务配置
与Spring配置中心一样,需要总线和接口监控组件,
集成bus-amqp和actuator。
4.1 依赖
依赖如下:
<!-- 服务注册和发现、客户端负载均衡、熔断 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<!-- Config客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<!-- 总线amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- 监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
4.2 配置参数
直接使用bootstrap.yml,内容如下:
说明:不配置application.yml,因为没有使用config配置中心时,application.yml配置了其他的环境文件(application-dev.yml等),
当使用config配置中心的文件测试时,使用公共环境文件替代了项目中的环境文件(application-dev.yml等)。
spring:
cloud:
config:
discovery:
enabled: true # 开启发现spring-config服务
service-id: config # spring-config服务ID
name: application # spring-config服务中的配置文件前缀
profile: dev # spring-config服务中的配置文件后缀,完整:application-dev.yml
rabbitmq:
host: localhost
port: 5672
username: xindaqi
password: 123456
publisher-confirm-type: correlated
publisher-returns: true
virtualHost: /tutorial
listener:
direct:
acknowledge-mode: manual
simple:
acknowledge-mode: manual
concurrency: 1
max-concurrency: 1
retry:
enabled: true
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8001/eureka/eureka
management: # 暴露监控路径
endpoints:
web:
exposure:
include: bus-refresh
4.3 接口
为测试配置自动刷新,使用@Value读取配置配置my.config,
使用@RefreshScope触发获取变更的数据,样例如下:
package com.monkey.common.api;
import com.monkey.common.common.response.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 配置数据接口.
*
* @author xindaqi
* @since 2022-10-28 17:46
*/
@RestController
@RequestMapping("/api/v1")
@RefreshScope
public class ConfigDataApi {
@Value("${spring.datasource.url}")
String datasourceUrl;
@Value("${my.config}")
String myConfig;
@GetMapping("/datasource/url")
public Response<String> getDatasourceUrl() {
return Response.success(datasourceUrl);
}
@GetMapping("/my-config")
public Response<String> getMyConfig() {
return Response.success(myConfig);
}
}
第一次的读取配置文件结果如下图所示。
当Spring配置中心变更数据时,对应的其他客户端(连接到配置中心的服务)监听的队列会同步获取到消息,
日志信息如下图所示。
更直观的展示通过RabbitMQ监控面板可以看到,如下图所示,
由图可知,有新的数据入队,并被消费,此时,该服务内存中的配置数据已自动更新。
第二次的读取配置文件结果如下图所示,数据自动更新成功。
5 小结
(1)自动同步更新配置中心数据:通过bus-amqp和开放刷新接口实现;
(2)Spring配置中心和其他连接到配置中心的服务会各自监听一个队列,同步消息;
(3)在配置中心刷新数据,并通过总线方式,同步消息到其他队列,其他服务通过@RefreshScope更新数据。