好了如今咱们接着上一篇的随笔,继续来说。上一篇咱们讲到,咱们若是要去更新全部微服务的配置,在不重启的状况下去更新配置,只能依靠spring cloud config了,可是,是咱们要一个服务一个服务的发送post请求,html
咱们能受的了吗?这比以前的没配置中心好多了,那么咱们如何继续避免挨个挨个的向服务发送Post请求来告知服务,你的配置信息改变了,须要及时修改内存中的配置信息。java
这时候咱们就不要忘记消息队列的发布订阅模型。让全部为服务来订阅这个事件,当这个事件发生改变了,就能够通知全部微服务去更新它们的内存中的配置信息。git
这时Bus消息总线就能解决,你只须要在springcloud Config Server端发出refresh,就能够触发全部微服务更新了。web
Spring Cloud Bus除了支持RabbitMQ的自动化配置以外,还支持如今被普遍应用的Kafka。在本文中,咱们将搭建一个Kafka的本地环境,并经过它来尝试使用Spring Cloud Bus对Kafka的支持,实现消息总线的功能。spring
window下安装kafka和zooker,超详细:https://blog.csdn.net/weixin_33446857/article/details/81982455apache
kafka:安装下载教程网址(CentOS Linux):http://www.javashuo.com/article/p-uezkozpd-ez.htmlbootstrap
zooker的下载安装网址:https://blog.csdn.net/ring300/article/details/80446918app
项目: 一个服务端。2个客户端。maven
pom文件:spring-boot
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>springcloud_serviceClient2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-kafka</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<!--Spring Boot Actuator,感应服务端变化-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
client1的配置文件要改成bootstrap.yml,由于这种配置格式,是优先加载的,上一篇随笔有讲过,client2的配置以下:
server: port: 7008 spring: application: name: config2 cloud: config: label: master #启动什么环境下的配置,dev 表示开发环境,这跟你仓库的文件的后缀有关,好比,仓库配置文件命名格式是cloud-config-dev.properties,因此profile 就要写dev profile: dev name: cloud-config discovery: enabled: true #这个名字是Config Server端的服务名字,不能瞎写。 service-id: CONFIG-SERVER management: #是否须要权限拉去,默认是true,若是不false就不容许你去拉取配置中心Server更新的内容 security: enabled: false #注册中心 eureka: client: service-url: defaultZone: http://localhost:8001/eureka/
启动类:
package cn.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ClientApplication2 { public static void main(String[] args) { SpringApplication.run(ClientApplication2.class, args); System.out.println("启动成功!");
controller类:
package cn.demo.web; 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope public class Controller { /*@Value("${spring.cloud}") private String config; @GetMapping("/test/config") public String test() { return config; }*/ @Value("${name}") private String name; @Value("${age}") private Integer age; @RequestMapping("/test") public String test(){ return this.name+this.age; } }
接着将client2中的的代码基本和client的同样,只是暴露服务的端口不一样。
而后:
把zooker,kafka启动;(标题下面连接)
把前面的工程,1个注册中心,一个springcloud-config-server,两个springcloud-config-client,springcloud-config-client1启动起来,
能够看到springcloudBus是在0分片上,若是两个config-client启动都出现上面信息,证实启动成功了。
访问:http://localhost:7000/cloud-config-dev.properties
再访问两个client,以下:
http://localhost:7006/test http://localhost:7008/test
好了,好戏开始了,如今咱们去git仓库上修改配置中心的文件,将年龄改成24,以下:
接下来,咱们咱们用refresh刷新配置服务端7000配置,通知两个client去更新内存中的配置信息。用postman发送localhost:7000/bus/refresh,以下:
注意:spring1.x和spring2.x 刷新的路径不同。
----------------------------------------------------
看一下返回的结果:
能够看到没有返回什么信息,可是不要担忧,这是成功的通知全部client去更新了内存中的信息了。
接着咱们分别从新请求config-server,两个client,刷新页面,结果以下:
到目前为止,上面都是刷新说有的配置的信息的,若是咱们想刷新某个特定服务的配置信息也是能够的。咱们能够指定刷新范围,以下:
上面的例子中,咱们经过向服务实例请求Spring Cloud Bus的/bus/refresh
接口,从而触发总线上其余服务实例的/refresh
。可是有些特殊场景下(好比:灰度发布),咱们但愿能够刷新微服务中某个具体实例的配置。
Spring Cloud Bus对这种场景也有很好的支持:/bus/refresh
接口还提供了destination
参数,用来定位具体要刷新的应用程序。好比,咱们能够请求/bus/refresh?destination=服务名字:9000
,此时总线上的各应用实例会根据destination
属性的值来判断是否为本身的实例名,
若符合才进行配置刷新,若不符合就忽略该消息。
destination
参数除了能够定位具体的实例以外,还能够用来定位具体的服务。定位服务的原理是经过使用Spring的PathMatecher(路径匹配)来实现,好比:/bus/refresh?destination=customers:**
,该请求会触发customers
服务的全部实例进行刷新。