Bus组件的使用

上次写到用curl去手动刷新配置,这样不现实,那么就需要一种机制去实现自动刷新配置,这就要用到消息总线Bus组件了,概念:

1.PNG
根据定义和结构图,我们需要先将configserver和configclient挂在一处消息总线上为了以后做消息广播,所以需要中间件RabbitMQ,MQ就是消息队列(消息:数据传输 队列:一种先进先出,后进后出的数据结构,和栈相反),先在windows上安装MQ:

可以直接参照:

windows10环境下的RabbitMQ安装步骤(图文)

搭建好后进入mq默认控制台localhost:15672 , 用户名密码都输入guest进入首页

2.PNG

这样消息中间件MQ就搭起来了,然后就是要把configserver和configclient也挂到MQ上,比较简单,老规矩:引依赖、写配置即可,所有微服务都要写该依赖(只要你想挂到MQ上):

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


configserver中写连接MQ的配置,要注意所有的configclient都没必要写到配置里,可以交给远程库去管理:

spring.rabbitmq.host=localhos     #连接主机
spring.rabbitmq.port=5672	  #连接mq端口
spring.rabbitmq.username=user	  #连接mq用户名
spring.rabbitmq.password=password #连接mq密码

3.PNG

然后分别启动configserver和configclient,configserver正常启动,但是configclient启动会报错,因为把client连接mq的配置写在了远程库,在启动client时默认会立即去注册到MQ上,但是此时配置文件还没有拉取下来,所以client会直接启动失败,需要加一个配置:

#启动时当远端配置还没有拉取完成时,项目启动过程中所有失败都是允许的
spring.cloud.config.fail-fast=true

这样的话就都可以正常启动了,也都挂在mq上了

4.PNG

执行curl指令可以实现配置的统一刷新(curl的是configserver):

curl -X POST http://localhost:port/actuator/bus-refresh

默认情况下使用curl -X POST http://localhost:port/actuator/bus-refresh这种方式刷新配置是全部广播形式,也就是所有的微服务都能接收到刷新配置通知,但有时我们修改的仅仅是某个服务的配置,这个时候对于其他服务的通知是多余的,因此就需要指定服务进行通知,也是执行curl

指定服务刷新配置实现
指定端口刷新某个具体服务: curl -X POST http://localhost:port/actuator/bus-refresh/configclient:port
指定服务id刷新服务集群节点: curl -X POST http://localhost:port/actuator/bus-refresh/configclient
[注意:][configclient代表刷新服务的唯一标识]
集成webhook实现自动刷新

webhook本质是一种监听机制,用钩子函数实现,简单理解就是点击提交按钮(这是一个事件)然后就去触发某些函数(处理该事件)

实现方式也比较简单,只需要在远程库的设置里配置上面curl 那个bus-refresh接口的路径就行(configserver),但是有一点,我路径里要是配localhost地址,远程库肯定啥也找不到,这时候就需要内网穿透工具暂时使我们内网对外,或者直接把项目挂公网也可以啦,这里就先用内网穿透吧,用natapp来搞,以前做微信公众号时经常用这个工具做测试嗷。

去官网注册,创建免费隧道(有钱建议支持下vip隧道),配置好要穿透的服务的对应端口(我这里要穿的就是configserver),下载客户端,安装很简单,要注意是cmd启动,不是exe,官网:https://natapp.cn/。执行

natapp -authtoken yourtoken

5.PNG

然后去远程库设置的webhooks中添加该域名

6.PNG

可以在查看更多里查看请求历史(查看请求状态)

现在webhook就挂上了,先看看修改前的配置文件,请求一下服务看下返回:

7.PNG

现在修改配置文件内容,看下日志,postman再请求下client接口,可以发现自动刷新配置已经可以实现了:

9.PNG

8.PNG

在远程库添加webhook时会遇到400的错误,需要在configserver中加一个urlfilter:

package com.jin.config;

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;

/**
 * @author jinyunlong
 * @date 2021/7/21 16:37
 * @profession ICBC锅炉房保安
 */
@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((ServletRequest) 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();
    }
}

@ServletComponentScan(basePackages = "com.jin.config")   //启动类添加扫描包注解

补一点,curl 配置中心时要是报错别忘了在配置文件里加一个开启web端点暴露:

#开启所有web端点暴露 为了访问curl -X POST http://localhost:port/actuator/bus-refresh
management.endpoints.web.exposure.include=* 
SpringCloud 微服务工具集总结

小结一下,就直接贴图了:

44.springcloud总结.png

可以看到有的组件用到了耐非的,有的用到Spring的,还有google的等等,还有不少好组件是alibaba的,就是接下来要看的spring alibaba封装的组件了。


标题:再战SpringCloud(7)
作者:jyl
地址:http://jinyunlong.xyz/articles/2021/07/23/1627009544759.html