背景
结合前面【SpringCloud】SpringCloud Config分布式配置中心中的Config客户端之动态刷新出现的问题:不重启客户端的情况下,每个客户端都需要发送Post请求刷新,在客户端较多的情况下比较麻烦,而Spring Cloud Bus配合Spring Cloud Config使用可以实现配置的动态刷新,达到一次发送,处处生效
什么是SpringCloud Bus
- Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架,它整合了Java的事件处理机制和消息中间件的功能。
- Spring Clud Bus目前支持RabbitMQ和Kafka。
- 在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统中所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称它为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息。
SpringCloud Bus的使用
Bus支持两种消息代理:RabbitMQ和Kafka,下面是以RabbitMQ为例,需要进行RabbitMQ环境配置,如果你没有配,建议先产靠博客:RabbitMQ环境配置,配置好环境。
添加一个客户端
- 新建一个客户端Module,cloud-config-client-3366
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringcloudTest</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-config-client-3366</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 配置文件:bootstrap.yml
server:
port: 3366
spring:
application:
name: config-client
cloud:
config:
label: master
name: config
profile: dev
uri: http://localhost:3344
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
management:
endpoints:
web:
exposure:
include: "*"
- 主启动类:
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3366 {
public static void main(String[] args) {
SpringApplication.run( ConfigClientMain3366.class,args);
}
}
- 业务类:
@RestController
@RefreshScope
public class ConfigClientController {
@Value("${server.port}")
private String serverPort;
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo(){
return "serverPort:"+serverPort+"\t\n\n configInfo: "+configInfo;
}
}
设计思想
- 利用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置
- 利用消息总线触发一个服务端ConfigServer的/bus/refresh端点,而刷新所有客户端的配置
小结: 上面两种思想都是可以实现的,第一种是通过触发一个客户端,而刷新所有客户端,第二种是通过触发Config服务端,刷新所有的客服端,很明显第二种更加符合实际,推荐使用第二种,后面也会采用第二种来实现。
正式使用Bus
- 给cloud-config-center-3344配置中心服务端添加消息总线支持
(1)添加pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
(2)添加配置【添加了rabbitmq和management】
server:
port: 3344
spring:
application:
name: cloud-config-center
cloud:
config:
server:
git:
uri: https://github.com/hezhegit/sprincloud-config.git
search-paths:
- springcloud-config
label: master
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
- 给cloud-config-center-3355和cloud-config-client-3366客户端添加消息总线支持
(1)添加pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
(2)添加配置【添加了rabbitmq】
spring:
application:
name: config-client
cloud:
config:
label: master
name: config
profile: dev
uri: http://localhost:3344
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
- 测试:
(1)开启RabbitMQ,然后开启7001、7002Eureka集群,3344ConfigServer,3355,3366ConfigClient
(2)分别访问http://localhost:3344/master/config-dev.yml、http://localhost:3355/configInfo和http://localhost:3366/configInfo,version都为3
(3)修改github上面的version,改为4
继续访问上面网址只有ConfigServer刷新了version,客户端全为3,没有刷新
(4)因为我们给3344服务端配置了总线,我们只需要给3344发送一个Post请求,即可达到一次发送,处处生效。curl -X POST "http://localhost:3344/actuator/bus-refresh"
继续访问3355、3366,可以看到version=4
- 上面达到了一次通知,处处生效的效果,但是我不想全部通知,只想定点通知该怎么办:
/bus/refresh请求不再发送到具体的服务实例上,而是发给config server并通过destination参数类指定需要更新配置的服务或实例,公式:http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}
例如:我们通知3355,不通知3366:curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
(1)修改version为5
(2)执行curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"
(3)访问3355、3366