Spring Cloud Config自动刷新配置

目录

一、服务端配置

二、客户端配置

三、客户端使用

四、使用Gitlab Webhook自动刷新

五、Webhook测试异常

六、Webhook异常处理

一、服务端配置

增加SpringCloud bus等依赖:

pom.xml
1
2
3
4
5
6
7
8
9
<!-- springcloud-bus依赖实现配置自动更新,rabbitmq -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置文件增加RabbitMQ地址、暴露节点等配置

bootstrap.yml
1
2
3
4
5
6
7
8
9
10
11
12
spring:
  # rabbitmq 地址配置
  rabbitmq:
    host: 172.18.0.118
    port: 32139
    username: guest
    password: guest
management:
  endpoints:
    web:
      exposure:
        include: "*"

二、客户端配置

添加SpringCloud bus等依赖

pom.xml
1
2
3
4
5
6
7
8
9
<!-- springcloud-bus依赖实现配置自动更新,rabbitmq -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

配置文件增加RabbitMQ地址配置

bootstrap.yml
1
2
3
4
5
6
7
spring:
  # rabbitmq 地址配置
  rabbitmq:
    host: 172.18.0.118
    port: 32139
    username: guest
    password: guest

三、客户端使用

增加@RefreshScope注解

Demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping("/ctrl")
@RefreshScope
public class TestController {
 
 
    @Value("${chipcloud-service.endpoints.demo-test2.path:xxxxxxxxxxxxxx}")
    private String test;
 
    @RequestMapping("/test")
    public String getName(){
        System.out.println("===================>"+test);
        return "Success!";
    }
}

此时,当Config配置文件变化后,客户端读到的配置信息仍然是旧数据,需要手动请求   POST   http://配置中心IP:PORT/actuator/bus-refresh 触发刷新。下面第四节通过Gitlab webhook代替该手动触发POST请求(仅需在配置中心仓库配置一次即可)。

四、使用Gitlab Webhook自动刷新

Gitlab→zkxy-config→Settings→Integrations

点击Test→Push events进行测试:

 

五、Webhook测试异常

Push events进行测试,出现  400  的Http Status Code:

Request headers
Content-Type: application/json
X-Gitlab-Event: Push Hook
Request body 
{
  "object_kind""push",
  "event_name""push",
  "before""243ce5486e9ef3ffa974337e550c0444daefa132",
  "after""ddeb8cb816fe96905686deb0418be245aebc1c48",
  "ref""refs/heads/master",
  "checkout_sha""ddeb8cb816fe96905686deb0418be245aebc1c48",
  "message"null,
  "user_id": 11,
  "user_name""zouxiaodong",
  "user_username""zouxiaodong",
  "user_email""",
  "project_id": 14,
  "project": {
    "id": 14,
    "name""zkxy-config",
    "description""spring-cloud-config 分布式配置中心",
    "avatar_url"null,
    "git_ssh_url""git@172.18.0.103:proof/zkxy-config.git",
    "git_http_url""http://172.18.0.103/proof/zkxy-config.git",
    "namespace""proof",
    "visibility_level": 20,
    "path_with_namespace""proof/zkxy-config",
    "default_branch""master",
    "ci_config_path"null,
    "url""git@172.18.0.103:proof/zkxy-config.git",
    "ssh_url""git@172.18.0.103:proof/zkxy-config.git",
  },
  "commits": [
    {
      "id""ddeb8cb816fe96905686deb0418be245aebc1c48",
      "message""解决webhook返回400错误码的问题\n",
      "timestamp""2020-09-02T07:44:13Z",
      "author": {
        "name""zouxiaodong",
        "email""zouxd@chip-cloud.com"
      },
      "added": [
        "src/main/java/com/zkxy/edaStation/zkxy_config/WebHooksFilter.java"
      ],
      "modified": [
 
      ],
      "removed": [
 
      ]
    }
  ],
  "total_commits_count": 1,
  "push_options": {
  },
  "repository": {
    "name""zkxy-config",
    "url""git@172.18.0.103:proof/zkxy-config.git",
    "description""spring-cloud-config 分布式配置中心",
    "git_http_url""http://172.18.0.103/proof/zkxy-config.git",
    "git_ssh_url""git@172.18.0.103:proof/zkxy-config.git",
    "visibility_level": 20
  }
}
Response headers
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 02 Sep 2020 07:44:16 GMT
Connection: close
Response body
{"timestamp":"2020-09-02T07:44:16.576+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 1, column: 459] (through reference chain: java.util.LinkedHashMap[\"project\"])","path":"/actuator/bus-refresh"}

六、Webhook异常处理

出现上述异常信息是因为POST请求会携带Request Body发送至配置中心服务器,Request Body使用JSON解析时出错,无法反序列化,抛出异常,返回400错误。WebHook POST的请求附加的内容对于动态修改配置文件不重要,可以把附加的内容信息清空掉,这时JSON解析就不会出错了。

通过Filter过滤器来拦截Http请求,清空servletRequest 中无法解析内容.

WebHooksFilter 
/**
 * @Description /actuator/bus-refresh 过滤器,清空/actuator/bus-refresh请求的Request body
 *
 * 解决Gitlab webhook触发配置中心/actuator/bus-refresh请求返回400错误码的问题
 *
 * Response body:
 * {"timestamp":"2020-09-02T07:21:31.728+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot
 * deserialize instance of `java.lang.String` out of START_OBJECT token;
 * nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream);
 * line: 1, column: 459] (through reference chain: java.util.LinkedHashMap[\"project\"])","path":"/actuator/bus-refresh"}
 * @Author zouxiaodong
 * @Date 2020/09/02 15:25
 */
@Component
public class WebHooksFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String url = httpServletRequest.getRequestURI();
        System.out.println("httpServletRequest.getRequestURI()=======>"+url);
        if(!url.endsWith("/bus-refresh")){
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
        filterChain.doFilter(requestWrapper, servletResponse);
    }
 
    private class RequestWrapper extends HttpServletRequestWrapper {
        public RequestWrapper(HttpServletRequest request) {
            super(request);
        }
 
        @Override
        public ServletInputStream getInputStream() throws IOException {
            byte[] bytes = new byte[0];
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            ServletInputStream servletInputStream = new ServletInputStream() {
                @Override
                public int read() throws IOException {
                    return byteArrayInputStream.read();
                }
 
                @Override
                public boolean isFinished() {
                    return byteArrayInputStream.read() == -1 ? true : false;
                }
 
                @Override
                public boolean isReady() {
                    return false;
                }
 
                @Override
                public void setReadListener(ReadListener listener) {
 
                }
            };
            return servletInputStream;
        }
    }
}

 
posted @ 2020-10-30 15:11  CoderZZZ  阅读(941)  评论(0编辑  收藏  举报