前面两篇文章我们聊了Spring Cloud Config配置中心,当我们在更新github上面的配置以后,如果想要获取到最新的配置,需要手动刷新或者利用webhook的机制每次提交代码发送请求来刷新客户端,客户端越来越多的时候,需要每个客户端都执行一遍,这种方案就不太适合了。使用Spring Cloud Bus(国人很形象的翻译为消息总线,我比较喜欢叫消息巴士)可以完美解决这一问题。

1. Spring Cloud Bus

Spring cloud bus通过轻量消息代理连接各个分布的节点。这会用在广播状态的变化(例如配置变化)或者其他的消息指令。Spring bus的一个核心思想是通过分布式的启动器对spring boot应用进行扩展,也可以用来建立一个多个应用之间的通信频道。目前唯一实现的方式是用AMQP消息代理作为通道,同样特性的设置(有些取决于通道的设置)在更多通道的文档中。

大家可以将它理解为管理和传播所有分布式项目中的消息既可,其实本质是利用了MQ的广播机制在分布式的系统中传播消息,目前常用的有Kafka和RabbitMQ。利用bus的机制可以做很多的事情,其中配置中心客户端刷新就是典型的应用场景之一,我们用一张图来描述bus在配置中心使用的机制。

根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:

  1. 提交到Git,Git触发post通过bus/refresh发送消息给我们的config-server
  2. config-server收到消息后从Git上的拉取最新配置,并发送消息给消息总线Spring Cloud Bus
  3. 所有config-client通过消息总线Spring Cloud bus接到通知后向config-server获取最新的配置信息
  4. 全部客户端均获取到最新的配置

以下是我对消息流程的理解手工图:

但是这个流程架构不是唯一的,还有下面这种直接webhook触发confi-client的,看图:

根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:

  1. 提交代码触发post给客户端A发送bus/refresh
  2. 客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus
  3. Spring Cloud bus接到消息并通知给其它客户端
  4. 其它客户端接收到通知,请求Server端获取最新配置
  5. 全部客户端均获取到最新的配置

重点说明:Git服务器的bus/refresh接口可以请求任何一个config-server地址或者任何一个config-client,因为他们是用spring cloud bus消息是相互连通的!!!

准备工作:我们这里用到了RabbitMQ,我们的SpringCloudBus需要依赖RabbitMQ消息队列来传播消息,安装RabbitMQ部分请查看我的另一篇文章最简单的RabbitMQ消息队列搭建(windows环境下安装)

一、修改config-server配置

server:
port: 8762
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/xulijun137/spring-cloud-config.git #配置文件所在仓库
###如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写。
username: username # 登录账号
password: password #登录密码
default-label: master #配置文件分支
search-paths: config1 #配置文件所在根目录
rabbitmq:
host: 127.0.0.1
prot: 5672
username: guest
password: guest
#暴露消息总线的地址,暴露/actuator/bus-refresh
management:
endpoints:
web:
exposure:
include: bus-refresh # 固定写法

看看我们的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xu</groupId>
<artifactId>config-server-8762</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config-server-8762</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.M3</spring-cloud.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <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> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> <repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories> </project>

二、修改config-client配置

server:
port: 8769
spring:
application:
name: config-bus
cloud:
config:
uri: http://localhost:8762
name: ronne-dev #配置文件名,不要扩展名yml
profile: dev #在项目名称后面-dev的内容,简介。
label: master #当configserver的后端存储是Git时,默认是master
rabbitmq:
host: 127.0.0.1
prot: 5672
username: guest
password: guest
#SpringCloud暴露接口,暴露/actuator/bus-refresh
management:
endpoints:
web:
exposure:
include: "*"

看看config-client的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xu</groupId>
<artifactId>service-consumer-bus-8761</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-consumer-bus-8761</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.M3</spring-cloud.version>
</properties> <dependencies>
<!--Spring Cloud 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>
<!--actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies> <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> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> <repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories> </project>

另外我们的Controller也需要添加一个注解(但是好像不加也行):

三、配置Git的/actuator/bus-refresh接口

首先要说明一点:这里可以配置任何一个config-server地址或者任何一个config-client地址都是可以的,因为他们是根据spring cloud bus消息是相互连通的!!!,当Git服务器上发生提交变动时候,就会给我们的config-server发送消息,告诉我们的配置中心的服务器及时拉取Git上最新的配置信息,登录到我们的GitHub,选择我们的配置文件的仓库:

关于下方怎么用NATAPP映射内网到外网,请继续看我的另一篇文章微信公众号开发之内网映射外网natapp安装(一),有详细的说明,具体的请登录NATAPP官网查看官网使用文档

拿到我们根据内网映射成的域名地址后,我们把 http://ndpn5z.natappfree.cc/actuator/bus-refresh这个地址配置到我们的webhook,记住请选择json方式提交(post方法提交)

接下来,我们依次启动config-sever和config-client这两个模块:

我们访问这个地址,http://localhost:8081/hello

然后我们去我们的GitHub上修改我们配置文件,然后保存修改

修改成功后,Git服务器就会给我们的config-server发送更新消息,我们的服务器就会自动拉取Git上的最新配置

这里需要说明的是如果你在本地测试的,你可以自己模拟外网的Git服务器给我们的config-server发送一个更新提心的消息,打开cmd窗口,输入curl -X POST http://localhost:8762/actuator/bus-refresh

我们还可以用IDEA提供的牛逼工具Test Restful Web Service来模拟一个webhook对我们的系统提交一个触发请求:

我们再次刷新我们的http://localhost:8081/hello,截图如下:

我们没有反复启动config-server就随时获取到了Git上修改(或者被提交的)最新信息,这就是SpringCloudBus的魅力和作用,谢谢观看,下次再见。

===============================================================================================

=======================================我是调皮的分割线==========================================

补充说明:我在配置我的仓库的webhooks的http://uyjzis.natappfree.cc/actuator/bus-refresh

这样之后提交最新的配置文件到GitHub之后,后台就会出现这个诡异的BUG错误:

大概的意思是GitHub发送了一个空的数据(不是空的JSON)给我们系统服务器,我们系统服务器表示不接受和不能解释这个空数据,这个应该是spring cloud bus的一个BUG,网上有网友提供一种思路,就是增加一个过滤器,就是在系统接受GitHub发来的这个空数据之前,我们把这个数据篡改成一个正常的空JSON,然后系统就能解释和理解这个“正常的”数据体了,下面是这个过滤器的代码:

package com.xu.eurekaserver.components;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException; public class FilterPayLoadWrapper extends HttpServletRequestWrapper {
public FilterPayLoadWrapper(HttpServletRequest request) { super(request);
} @Override
public ServletInputStream getInputStream() throws IOException {
final byte[] bytes = new byte[0];
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return byteArrayInputStream.read() == -1 ? true:false; } @Override
public boolean isReady() {
return false;
} @Override
public void setReadListener(ReadListener readListener) { } @Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
}

package com.xu.eurekaserver.components;

import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.stereotype.Component; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; /**
* @author lulu
* @Date 2019/7/1 22:51
*/
@Component
@ServletComponentScan
@WebFilter(urlPatterns = "/actuator/bus-refresh",filterName = "githubFilter")
public class GitHubHttpFilter implements Filter{ @Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)servletRequest;
filterChain. doFilter(new FilterPayLoadWrapper(request),servletResponse); } @Override
public void destroy() { }
}

经过我的实战测试,以上的过滤器是有效的,至此整个Spring Cloud Bus的基本内容就讲解到这里了。

最后,我把我的GitHub上的Webhooks配置成了我的config-client端,提交后client端也自动刷新拉取最新的云端配置信息了,也简单验证我之前上面说的config-server和config-client是通过bus互通的结论

===============================================================================

如果您觉得此文有帮助,可以打赏点钱给我支付宝或扫描二维码

SpringCloud学习之Bus消息总线实现配置自动刷新(九)的更多相关文章

  1. 多项目如何高效协同合作 | springcloud系列之bus消息总线

    前言 在springcloud config章节中我们完成了配种中心的搭建,以及通过配置中心完成配置的抽离通过springcloud config模块我们将配置抽离到git仓库中我们不必要每次为了改配 ...

  2. SpringCloud(六)Bus消息总线

    Bus 消息总线 概述 分布式自动刷新配置功能 Spring Cloud Bus 配合 Spring Cloud Config使用可以实现配置的动态刷新 Bus支持两种消息代理:RabbitMQ和Ka ...

  3. SpringCloud之Config配置中心+BUS消息总线原理及其配置

    一.配置中心作用 在常规的开发中,每个微服务都包含代码和配置.其配置包含服务配置.各类开关和业务配置.如果系统结构中的微服务节点较少,那么常规的代码+配置的开发方式足以解决问题.当系统逐步迭代,其微服 ...

  4. [转]springcloud(九):配置中心和消息总线(配置中心终结版)

    https://www.cnblogs.com/ityouknow/p/6931958.html springcloud(九):配置中心和消息总线(配置中心终结版) 我们在springcloud(七) ...

  5. 跟我学SpringCloud | 第八篇:Spring Cloud Bus 消息总线

    SpringCloud系列教程 | 第八篇:Spring Cloud Bus 消息总线 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 如无特 ...

  6. Spring Cloud(十一)高可用的分布式配置中心 Spring Cloud Bus 消息总线集成(RabbitMQ)

    详见:https://www.w3cschool.cn/spring_cloud/spring_cloud-jl8a2ixp.html 上一篇文章,留了一个悬念,Config Client 实现配置的 ...

  7. Spring Cloud 系列之 Bus 消息总线

    什么是消息总线 消息代理中间件构建一个共用的消息主题让所有微服务实例订阅,当该消息主题产生消息时会被所有微服务实例监听和消费. 消息代理又是什么?消息代理是一个消息验证.传输.路由的架构模式,主要用来 ...

  8. spring cloud bus 消息总线 动态刷新配置文件 【actuator 与 RabbitMQ配合完成】

    1.前言 单机刷新配置文件,使用actuator就足够了 ,但是 分布式微服务 不可能是单机 ,将会有很多很多的工程 ,无法手动一个一个的发送刷新请求, 因此引入了消息中间件 ,常用的 消息中间件 是 ...

  9. 通过总线机制实现自动刷新客户端配置(Consul,Spring Cloud Config,Spring Cloud Bus)

    通过总线机制实现自动刷新客户端配置 方案示意图 利用Git服务的webhook通知功能,在每次更新配置之后,Git服务器会用POST方式调用配置中心的/actuator/bus-refresh接口,配 ...

随机推荐

  1. vue - data 接收 props 的值

    <template>   <div>     <div v-for="todo in a" :key="todo.id"> ...

  2. 挖洞经验 | 绕过WAF限制利用php:方法实现OOB-XXE漏洞利用

    几个星期以前,作者在某个OOB-XXE漏洞测试中遇到过这样一种场景:目标应用后端系统WAF防火墙阻挡了包含DNS解析在内的所有出站请求(Outgoing Request),但最终,通过利用php:// ...

  3. python 数据处理 对csv文件进行数据处理

    数据如下图: 用python对数据进行处理: #读取csv文件内容并进行数据处理 import os import csv import datetime import re from itertoo ...

  4. 关于 vue.config.js 文件的配置

    相关文档: https://cli.vuejs.org/zh/config/#vue-config-js

  5. c# GlobalAddAtom GlobalDeleteAtom

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  6. Netty 中队列的使用

    任务队列中的Task有3种典型使用场景 用户程序自定义的普通任务 此前代码: 参考https://www.cnblogs.com/ronnieyuan/p/12016712.html NettySer ...

  7. mysql数据库可视化工具—Navicat Premium—安装与激活

    一.Navicat premium简介 Navicat premium是一款数据库管理工具.将此工具连接数据库,你可以从中看到各种数据库的详细信息.包括报错,等等.当然,你也可以通过他,登陆数据库,进 ...

  8. Java For 循环

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...

  9. Window Server 2019 配置篇(2)- 在window server core上安装网络跟DHCP服务

    上一篇我们已经建立了自己的域服务器 之后我们将安装一个window server core,也就是没有GUI只有命令行的window server,并在其上安装网络服务和DHCP 首先创建一个新的虚拟 ...

  10. Arch系linux配置Go开发环境

    1. 下载go $ sudo pacman -S go 下载后系统会将go安装在/usr/lib/go目录下 2. 配置一些环境变量 一共需要三个环境变量,分别为: GOROOT -> go语言 ...