12.统一配置中心config自动刷新组件之bus(代码片段)

潮汐先生 潮汐先生     2022-12-07     155

关键词:

前言

在上一节11.Config统一配置中心之手动刷新中我们是现在手动刷新获取远端Git仓库的配置文件。我们也知道了手动刷新这种方式的诸多问题。这一节我们将要学习springcloud官方提供的自动刷新组件–spring-cloud-bus,以下简称Bus

什么是Bus

Spring Cloud Bus links nodes of a distributed system with a lightweight message broker. This can then be used to broadcast state changes (e.g. configuration changes) or other management instructions. AMQP and Kafka broker implementations are included with the project. Alternatively, any Spring Cloud Stream binder found on the classpath will work out of the box as a transport.

官网给出了这么一大坨解释,具体是什么意思呢?

Bus称之为SpringCloud中的消息总线,主要用来在微服务系统中实现远端配置更新时通过广播形式通知所有客户端刷新配置信息,避免手动重启服务的工作。

Bus利用轻量级消息中间件将分布式系统中所有的服务连接到一起

当配置文件(当前状态)发生改变时,Bus利用消息中间件的广播特性通知响应的关联服务更新自身配置(当前状态)

刷新原理

在这里插入图片描述

刷新实现

安装RabbitMQ

上面我们说了Bus的工作原理是利用了轻量级消息中间件将分布式系统中所有的服务连接到一起。这里我们的消息中间件选择RabbitMQ。

RabbitMQ的具体安装教程参考文章RabbitMQ入门之基础理论

从上面的原理图上我们能够看到不论是Config Server还是Config Client都需要连接上RabbitMQ,下面我们先看下Config Server。

Config Server端配置

1.pom.xml

首先我们需要在pom.xml文件中引入bus的依赖

<?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>springcloud_parent</artifactId>
        <groupId>com.christy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>07.springcloud_config_server</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入consul client依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!-- 引入健康检查依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!--引入统一配置中心-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

        <!--引入bus依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
    </dependencies>
</project>

2.application.properties

server.port=8910
spring.application.name=CONFIGSERVER

#注册服务中心
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500

# 配置远程仓库
# 指定仓库的url
spring.cloud.config.server.git.uri=https://gitee.com/tide001/config-server.git
# 指定访问的分支
spring.cloud.config.server.git.default-label=master

# 如果是私有仓库 需要配置用户名和密码
#spring.cloud.config.server.git.username=
#spring.cloud.config.server.git.password=

# 配置RabbitMQ
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/

3.重新启动Config Server

上面两步配置完毕后Config Server端的配置就算是结束了,现在我们重启Config Server。重启完Server端以后我们可以看到在RabbitMQ的Queue里面多了一个名字为Queue springCloudBus.anonymous.frByGl79R7y0HX0RSHMggg的队列

在这里插入图片描述

Config Client端配置

1.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>springcloud_parent</artifactId>
        <groupId>com.christy</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>07.springcloud_config_client</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- 引入springboot依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 引入consul client依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</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-config</artifactId>
        </dependency>

        <!--引入bus依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
    </dependencies>
</project>

这个bus依赖在所有需要自动刷新的节点上都需要配置

2.修改配置文件

client端的配置文件仍需要配置RabbitMQ,只不过这个我们需要配置在远端git仓库中的配置文件configclient.properties中

server.port=8911
spring.application.name=CONFIGCLIENT

# spring.profile.active=dev

# 配置RabbitMQ
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/

client端在上述两步完成后仍然不能重亲启动,否则会报以下错误

在这里插入图片描述

这个是什么原因导致的呢?

我们在引入bus组件后,在项目(系统)启动的时候会去加载RabbitMQ的配置以启动并连接消息中间件。这个时候我们从远端仓库中加载的配置文件尚未拿到,所以报了这个错

解决方案

在bootstrap.properties中新增spring.cloud.config.fail-fast=true,意思是在启动时还没有拉取远端配置完成时的失败都是允许的

3.bootstrap.properties

# 配置注册中心
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500

# 告诉当前Config Client统一配置中心在注册中心的服务id
spring.cloud.config.discovery.service-id=CONFIGSERVER
# 开启当前Config Client 根据服务id去注册中心获取
spring.cloud.config.discovery.enabled=true

# 获取那个配置文件 1.确定分支  2.确定文件名  3.确定环境
spring.cloud.config.label=master
spring.cloud.config.name=configclient
spring.cloud.config.profile=dev

management.endpoints.web.exposure.include=*

# 在启动时还没有拉取远端配置完成时的失败都是允许的
spring.cloud.config.fail-fast=true

4.测试

现在我们重新启动Config Client,发现这次是可以正常启动的。我们修改远端的配置文件如下:

在这里插入图片描述

此时我们去访问http://localhost:8911/test/hello,发现结果并不是我们修改的结果

在这里插入图片描述

这是因为我们在Config Server端的配置少了一步:通过执行post接口刷新配置。通过上一篇文章11.Config统一配置中心之手动刷新我们知道想要执行post接口刷新配置必须开启web端点暴露

这里需要注意:

上一篇手动刷新配置是在Client端执行post接口进行刷新配置

而本节说的自动刷新配置执行post接口是在Server端执行post接口进行刷新配置,这相较于Client端节省了大量的工作

开启Server端的web端点暴露

1.application.properties

server.port=8910
spring.application.name=CONFIGSERVER

#注册服务中心
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500

# 配置远程仓库
# 指定仓库的url
spring.cloud.config.server.git.uri=https://gitee.com/tide001/config-server.git
# 指定访问的分支
spring.cloud.config.server.git.default-label=master

# 如果是私有仓库 需要配置用户名和密码
#spring.cloud.config.server.git.username=
#spring.cloud.config.server.git.password=

# 配置RabbitMQ
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/

# 开启所有的web端点暴露
management.endpoints.web.exposure.include=*

2.重新启动Config Server

3.执行POST接口

我们这里直接在命令行的方式来执行,小伙伴们也可以在Postman中执行。打开命令行输入curl -X POST http://localhost:8910/actuator/bus-refresh

在这里插入图片描述

4.测试

我们再次在浏览器中输入http://localhost:8911/test/hello,发现结果已经更新

在这里插入图片描述

curl -X POST http://localhost:8910/actuator/bus-refresh这种方式是通过广播的方式通知所有连接到RabbitMQ的微服务同时更新,这显然是不合理而且浪费资源的。我们可以在上述命令的后面追加SERVER-ID来通过Config Server通知指定的SERVER刷新自身的配置:curl -X POST http://localhost:8910/actuator/bus-refresh/SERVER-ID

WebHook实现自动刷新

上面我们实现了配置的自动刷新,但是依然存问题:在Config Server端我们仍然需要手动执行POST访问,有没有更好的办法来自动执行Server端的POST访问?这就是我们下面要提到的webhook

什么 WebHook?

hook就是钩子,WebHooks是git(gitee|github)提供的一项功能,可以添加多个webHook

在这里插入图片描述

webHook能够根据仓库的触发事件去执行对应的操作。比如当我们修改了远程git仓库中的配置文件,当我们点击提交的时候它会自动发送一个POST的web请求,如果我们将该请求的url设置成Config Server的地址这就实现了自动执行Server端的POST访问,从而实现自动刷新的功能。

实现步骤

1.新增webHook

点击添加webHook,按照下图填写相关信息,点击添加即可

在这里插入图片描述

上图中的url是使用内网穿透映射的外网地址,具体的使用方法见文章natapp内网穿透速学教程

2.测试webHook

添加完毕后我们点击测试,发现返回400。如下图

在这里插入图片描述

3.解决方案

想要解决步骤2中的400,我们需要在Config Server中添加一个UrlFilter,如下

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;

@Component
public class UrlFilter  implements Filter 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
 
    
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        HttpServletRequest httpServletRequest = (HttpServletRequest)request;
        HttpServletResponse httpServletResponse = (HttpServletResponse)response;
 
        String url = new String(httpServletRequest.getRequestURI());
 
        //只过滤/actuator/bus-refresh请求
        if (!url.endsWith("/bus-refresh")) 
            chain.doFilter(request, response);
            return;
        
 
        //获取原始的body
        String body = readAsChars(httpServletRequest);
        System.out.println("original body:   "+ body);
 
        //使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
        CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
        chain.doFilter(requestWrapper, response);
    
 
    @Override
    public void destroy() 
 
    
 
    private class CustometRequestWrapper extends HttpServletRequestWrapper 
        public CustometRequestWrapper(HttpServletRequest request) 
            super(request);
        
 
        @Override
        public ServletInputStream getInputStream() throws IOException 
            byte[] bytes = new byte[0];
            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();
                
            ;
        
    
 
    public static String readAsChars(HttpServletRequest request) 
 
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder("");
        try 
            br = request.getReader();
            String str;
            while ((str = br.readLine()) != null) 
                sb.append(str);
            
            br.close();
        
        catch (IOException e) 
            e.printStackTrace();
        
        finally 
            if (null != br) 
                try  
                    br.close();
                
                catch (IOException e) 
                    e.printStackTrace();
                
            
        
        return sb.toString();
    

5.测试webHook

我们重启Config Server,然后测试我们上面添加的webHook,结果正常

在这里插入图片描述

6.测试自动刷新

我们启动Config Client,浏览器访问http://localhost:8911/test/hello,结果如下
在这里插入图片描述
此时,我们去git远程仓库修改配置文件如下
在这里插入图片描述
浏览器再次访问http://localhost:8911/test/hello,结果如下
在这里插入图片描述
从上面的结果可以看到我们已经成功使用webHook实现了通过Config Server自动执行POST请求实现Config Client配置文件的自动刷新O(∩_∩)O哈哈~

本系列专题源码已经上传至gitee:https://gitee.com/tide001/springcloud_parent,欢迎下载交流

11.config统一配置中心之手动刷新(代码片段)

Config统一配置中心之手动刷新前言手动刷新配置实现步骤1.@RefreshScope2.TestController.java3.开启所有web端点暴露4.启动5.修改远端配置文件6.手动刷新配置文件7.测试存在的问题前言在上篇文章10.微服务全局配置中心之Config中我们实... 查看详情

config配置中心之自动刷新

...布式的节点用轻量的消息代理连接起来。它可以用于广播配置文件的更改或者服务之间的通讯,也可以用于监控。本文要讲述的是用SpringCloudBus实现通知微服务架构的配置文件的更改,即实现配置中心的自动刷新和批量更新。这... 查看详情

springcloud系列之config配置中心

...章,未读第一集的同学请猛戳这里:SpringCloud系列之Config配置中心(一)本篇文章讲解Config如何实现配置中心自动刷新。配置中心自动刷新点击链接观看:配置中心自动刷新视频(获取更多请关注公众号「哈喽沃德先生」)SpringC... 查看详情

springcloud学习系列之五-----配置中心(config)和消息总线(bus)完美使用版(代码片段)

...于SpringCloud(基于SpringBoot2.x,.SpringCloudFinchley版)中的分布式配置中心(SpringCloudConfig)的配置刷新和消息总线(RabbitMQ和Kafka)使用教程。SpringCloudConfigRefresh在上一篇中我们介绍了springcloud配置中心的本地使用 查看详情

springcloud学习系列之五-----配置中心(config)和消息总线(bus)完美使用版(代码片段)

...于SpringCloud(基于SpringBoot2.x,.SpringCloudFinchley版)中的分布式配置中心(SpringCloudConfig)的配置刷新和消息总线(RabbitMQ和Kafka)使用教程。SpringCloudConfigRefresh在上一篇中我们介绍了springcloud配置中心的本地使用 查看详情

springcloudconfig(统一配置中心)

参考技术Apom.xmlApplication.javaapplication.yml测试访问:pom.xmlbootstrap.yml注意:如果Eureka端口被修改,则eureka.client的配置不能放到git远端Server端和Client端的pom.xml加上测试启动成功后在RabbitMQ上查看bus是否创建了消息队列docker安装RabbitMQ-... 查看详情

springcloud系列之configbusstreamsleuth(代码片段)

...(四)之Config、Bus、Stream、Sleuth一、Config分布式配置中心1.1概述1.2基本使用1.2.1Config服务端配置与测试1.2.1.1Git远程服务器配置1.2.1.2服务端配置测试1.2.1.3git远程仓库配置文件读取规则1.2.2Config客户端配置与测试1.3分布式配... 查看详情

springcloud-config配置中心初级篇

...就非常不方便,springcloud官方推出了config配置中心,用于统一管理配置文件;配置中心实现的大体流场如下:客户端从服务端获取配置文件,通常服务端需要负载均衡和高可用;服 查看详情

Spring Cloud Config Server/Bus 自动刷新扩展性

...03-1511:30:49【问题描述】:据我所知,当SpringCloudConfigServer配置更改时,可以通过SpringCloudBus在微服务之间传播刷新事件。然后,这会触发通知的微服务从SpringCloudConfig 查看详情

03.nacos组件之统一配置中心(代码片段)

Nacos组件之统一配置中心前言介绍核心概念命名空间GroupDataIDconfigclient-profile.propertiesConfigClient开发1.新建Module2.pom.xml3.bootstrap.properties4.ConfigClientApplication.java5.TestController.java6.测试历史版本前言前面我们提到过Nacos是ali 查看详情

5.springcloud--配置中心config消息总线bus链路追踪sleuth配置中心nacos(代码片段)

5.SpringCloud--配置中心Config、消息总线Bus、链路追踪Sleuth、配置中心Nacos一、引入配置中心1.1问题与解决二、配置中心--Config2.1Config是什么?(1)Config是什么?(2)Config功能2.2搭建配置中心(ConfigServer... 查看详情

多项目如何高效协同合作|springcloud系列之bus消息总线(代码片段)

...loudconfig章节中我们完成了配种中心的搭建,以及通过配置中心完成配置的抽离通过springcloudconfig模块我们将配置抽离到git仓库中我们不必要每次为了改配置而发包了。但是springcloudconfig并没有彻底的帮我们解决配置自动更新... 查看详情

springcloud微服务(06):config组件,实现配置统一管理

本文源码:GitHub·点这里||GitEE·点这里一、Config简介在微服务系统中,服务较多,相同的配置:如数据库信息、缓存、参数等,会出现在不同的服务上,如果一个配置发生变化,需要修改很多的服务配置。springcloud提供配置中心... 查看详情

springcloud系列之configbusstreamsleuth(代码片段)

...(四)之Config、Bus、Stream、Sleuth一、Config分布式配置中心1.1概述1.2基本使用1.2.1Config服务端配置与测试1.2.1.1Git远程服务器配置1.2.1.2服务端配置测试1.2.1.3git远程仓库配置文件读取规则1.2.2Config客户端配置与测试1.3分布式配... 查看详情

springcloud如何搭建config

...github,gitlab等上面,搭建自己的注册中心,完成对配置的统一管理和访问,后期我们会实现配置的动态刷新。把配置文件放在github上https://github.com/halouprogramer/spring-config-repositor 查看详情

多项目如何高效协同合作|springcloud系列之bus消息总线(代码片段)

...loudconfig章节中我们完成了配种中心的搭建,以及通过配置中心完成配置的抽离通过springcloudconfig模块我们将配置抽离到git仓库中我们不必要每次为了改配置而发包了。但是springcloudconfig并没有彻底的帮我们解决配置自动更新... 查看详情

多项目如何高效协同合作|springcloud系列之bus消息总线(代码片段)

...loudconfig章节中我们完成了配种中心的搭建,以及通过配置中心完成配置的抽离通过springcloudconfig模块我们将配置抽离到git仓库中我们不必要每次为了改配置而发包了。但是springcloudconfig并没有彻底的帮我们解决配置自动更新... 查看详情

多项目如何高效协同合作|springcloud系列之bus消息总线(代码片段)

...loudconfig章节中我们完成了配种中心的搭建,以及通过配置中心完成配置的抽离通过springcloudconfig模块我们将配置抽离到git仓库中我们不必要每次为了改配置而发包了。但是springcloudconfig并没有彻底的帮我们解决配置自动更新... 查看详情