一、手动刷新

1、创建GitHub远程仓库,把配置文件放到上边

测试示例:https://github.com/bjxPolestar/config-repo/tree/master/config-repo

2、需要搭建RabbitMQ(需要进行消息传递的)

3、Config Server端

3.1 pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

3.2 application.yml 

rabbitmq:
      host: 192.168.0.100
      port: 5672
      username: 用户名
      password: 密码

3.3 当configs erver和config client都往RabbitMQ发送消息时,还需要 手动地提交一个 /actuator/bus-refresh请求(该请求可以在远程仓库进行设置:当pull配置代码的时候,动态发送请求),所以需要进行一下参数设置,使其暴露该访问的路径

management:
  endpoints:
    web:
      exposure:
        include: "*"

服务端完整示例配置如下:

目录结构

spring boot 完成batch spring boot bus_spring boot 完成batch

application-dev.yml完整配置

spring:
  cloud:
    config:
      # enabled: true
      server:
        git:
          uri: https://github.com/bjxPolestar/config-repo.git
          search-paths: config-repo/dev-*
          #临时存储路径
          basedir: ../config-repo-temp
          username: *****
          password: ****
          force-pull: true #配置中心通过git从远程git库,有时本地的拷贝被污染,这时配置中心无法从远程库更新本地配置,设置force-pull=true,则强制从远程库中更新本地库
          default-label: master
    bus:
      enabled: true
      trace:
        enabled: true
  rabbitmq:
      host: 192.168.0.100
      port: 5672
      username: ***
      password: ***

application.yml完整配置

server:
  port: 8090 #${random.int(8090,8099)}
spring:
  application:
    name: cloud-config-server
  profiles:
    active: ${profileActive} #本地开发配置
eureka:
  client:
    serviceUrl:
      defaultZone: ${defaultZone}
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
    appname: cloud-config-server
management:
  endpoints:
    web:
      exposure:
        include: "*"

4.client server端

4.1 pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

4.2 application.yml 

rabbitmq:
      host: 192.168.0.100
      port: 5672
      username: 用户名
      password: 密码

5.手动刷新  使用postman 发送post请求http://localhost:8090/actuator/bus-refresh(8090为服务端config-server的端口)

spring boot 完成batch spring boot bus_ide_02

6.测试

客户端写测试代码:注意@RefreshScope注解不要忘

@RestController
@RefreshScope
@RequestMapping("/stu/student")
@Api(value = "/stu/student",tags="学生控制器")
public class GtStuStudentInfoRest extends BaseRest{
	
	
	@Value("${spring.datasource.initialSize}")
	private String driverClassName;
	
	@GetMapping("/getInitialSize")
	public String getDriver() {
		return driverClassName;
	}
}

启动完看一下你的MQ,如下图一样说明你的配置没有问题

spring boot 完成batch spring boot bus_spring_03

 访问: 

spring boot 完成batch spring boot bus_spring_04

 

 读取到值以后手动修改GitHub这个配置字段的值

spring boot 完成batch spring boot bus_java_05

然后postmain发送请求刷新在访问

spring boot 完成batch spring boot bus_java_06

此时值以改变,到此手动刷新配置已完成。本配置参考文档:

二、通过GitHub的webhook实现自动刷新

spring boot 完成batch spring boot bus_spring_07

注意坑:Payload URL需要设置成外网访问的地址,之前设置成了内网的IP地址,一直不通(需要进行内网穿透)。

配置完测试一直报错400,如下

Headers
Connection: close
Content-Length: 495
Content-Type: application/json;charset=UTF-8
Date: Wed, 19 Dec 2018 03:33:32 GMT
Transfer-Encoding: chunked
Body
{"timestamp":"2018-12-19T03:33:32.185+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token\n at [Source: (PushbackInputStream); line: 1, column: 295] (through reference chain: java.util.LinkedHashMap[\"commits\"])","path":"/actuator/bus-refresh"}

原因:集成webhook后,GitHub在进行post请求的同时默认会在body加上这么一串载荷,我们的spring boot因为无法正常反序列化这串载荷而报了400错误。

解决:修改body

servlet其实为我们提供了一个HttpServletRequestMapper的包装类,我们通过继承该类重写getInputStream方法返回自己构造的ServletInputStream即可达到修改request中body内容的目的。下面是代码,这里为了避免节外生枝我直接返回了一个空的body。
直接上硬货,代码如下:

import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * 解决使用spring cloud config bus使用webhook自动刷新出现的400问题
 * 
 * @auther lzp
 */
public 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();
			}
		};
	}

}
import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

import com.polestar.cloud.config.wrapper.CustometRequestWrapper;

/**
 * 过滤器
 * @auther lzp
 */
@WebFilter(filterName = "JsonFilter",urlPatterns = "/*")
public class JsonFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

		String url = new String(httpServletRequest.getRequestURI());

		// 只过滤/actuator/bus-refresh请求
		if (!url.endsWith("/bus-refresh")) {
			filterChain.doFilter(servletRequest, servletResponse);
			return;
		}

		// 使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
		CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);

		filterChain.doFilter(requestWrapper, servletResponse);
	}

	@Override
	public void destroy() {

	}

}

注意:启动类不要忘记加注解@ServletComponentScan扫描@WebFilter这个注解

spring boot 完成batch spring boot bus_java_08

最后测试成功:

spring boot 完成batch spring boot bus_java_09