一、使用/refresh端点手动刷新配置

很多场景下,需要在运行期间动态调整配置。如果配置发生了修改,微服务要如何实现配置的刷新呢?

1、复制config-client,重命名为config-client-refresh(端口:5021)

2、添加actuator依赖的jar

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

3、在Controller上添加@RefreshScope注解,添加@RefreshScope的类会在配置更改时得到特殊的处理

package com.liuy.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @description 描述
 * @author luis
 * @version 1.0
 * @date:2017年8月29日下午5:54:47
 */
@RestController
@RefreshScope
public class ConfigClientController {
	@Value("${profile}")
	private String profile;

	@GetMapping("/profile")
	public String hello() {
		return this.profile;
	}
}

4、测试

 a、访问http://localhost:5021/profile,获得结果:dev-1.0

 b、修改git仓库的spring-cloud-demo-dev.yml文件内容为:profile: dev-1.0-update

 c、重新访问http://localhost:5021/profile,获得结果:dev-1.0说明配置还没有更新

 d、POST请求http://localhost:5021/refresh

 e、再次访问http://localhost:5021/profile,获得结果:dev-1.0-update说明配置已经刷新

二、使用Spring Cloud Bus自动刷新配置

2.1、Spring Cloud Bus简介

Spring Cloud Bus使用轻量级的消息代理(如:RabbitMQ/kafaka)连接分布式系统的节点,这样就可以广播状态的更改(如:配置的更新)或者其它的管理指令。可将Spring Cloud Bus想象成一个分布式的Spring Boot Actuator。使用Spring Cloud Bus后的架构如下:

 wKioL1mo7tbB5lz8AADCoUeawuo846.png


A/B/C客户端都通过消息总线连接到了一起,每个客户端都会订阅配置更新事件。当其中一个微服务节点的/bus/refresh端点被请求时,该客户端就会向消息总线发送一个配置更新事件,其它客户端获得该事件后也会更新配置。

上面说明:

 a、提交代码触发post给客户端A发送bus/refresh

 b、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus

 c、Spring Cloud bus接到消息并通知给其它客户端

 d、其它客户端接收到通知,请求Server端获取最新配置

 e、全部客户端均获取到最新的配置

2.2、实现自动刷新

a、复制config-client-refresh项目,重命名为config-client-refresh-cloud-bus(端口:5021)

b、添加amqp依赖

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

c、修改bootstrap.yml

spring:
  application:
    # 对应config Server所获取的配置文件的{application}
    name: spring-cloud-demo 
  cloud:
    config:
      # config Server的地址
      uri: http://localhost:5020/
      # profile对应config Server所获取的配置文件的{profile}
      profile: dev
      # 指定git的分支,对应config Server所获取的配置文件的{label}
      label: master
  rabbitmq:
    host: 192.168.175.13
    port: 5672
    username: liuy
    password: 123456

d、复制一份config-client-refresh-cloud-bus,重命名为config-client-refresh-cloud-bus-2(端口:5022)

e、测试

 1、依次启动config-server、config-client-refresh-cloud-bus、config-client-refresh-cloud-bus-2。

 2、访问http://localhost:5021/profile,获取结果:dev-1.0-update

 3、修改git仓库的spring-cloud-demo-dev.yml文件内容为:profile: dev-1.0-update222

 4、POST请求http://localhost:5021/bus/refresh刷新配置

 5、访问http://localhost:5021/profilehttp://localhost:5022/profile,获取结果:dev-1.0-update222,说明配置内容已被刷新


补充:使用Git仓库的WebHooks,就可以轻松实现配置的自动刷新。

 wKiom1mo6VrCmQFnAAB7wIyWlu8768.png

2.3、局部刷新

某些场景下,如只想刷新部分微服务的配置,可通过/bus/refresh端点的destination参数来定位要刷新的应用程序。


如:/bus/refresh?destination=customers:9090,这样消息总线上的微服务实例就会根据destination参数的值来判断是否需要刷新。其中customers:9090指的是各个微服务的ApplicationContext ID。


destination参数也可以用来定位特定的微服务。例如:/bus/refresh?destination=customers:**,这样就可以触发customers微服务所有实例的配置刷新。


默认情况下ApplicationContext ID是spring.application.name:server.prot。

2.4、架构改进

通过请求某个微服务的/bus/refresh端点的方式来实现配置的刷新的方式并不优雅,原因如下:

 1、破坏了微服务的职责单一原则。业务微服务只应关注自身业务,不应该承担配置刷新的职责。

 2、破坏了微服务各节点的对等性。

 3、有一定的局限性。如:微服务在迁移时,网络地址常常会发送变化,此时如果想自动刷新配置,就不得不修改WebHook的配置。


改进:

 将Config Server也加入到消息总线中,并使用Config Server的/bus/refresh端点来实现配置的刷新。

 wKioL1mo71agZAdfAADAh9rYZ9M844.jpg

Config Server改动:(端口5020)

 a、添加依赖

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

 b、修改application.yml配置

server:
  port: 5020
#端点的配置
endpoints:
  sensitive: true
  shutdown:
    enabled: true
management:
  security:
    enabled: false
spring:
  profiles:
    active:
    - dev
  application:
    name: config-server-refresh-bus
  cloud:
    config:
      server:
        git:
          uri: https://git.oschina.net/wadjz/spring-cloud-config.git
          username: 
          password: 
  rabbitmq:
    host: 192.168.175.13
    port: 5672
    username: liuy
    password: 123456

刷新就可以访问:http://localhost:5020/bus/refresh 


2.5、跟踪总线事件

一些场景下如果希望知道Spring cloud Bus事件传播的细节,可以跟踪总线事件(Re-moteApplicationEvent的子类都是总线事件)。


想要跟踪总线事件非常简单,只须设置spring.cloud.bus.trace.enabled=true,这个在/bus/refresh端点被请求后,访问/trace端点就可获得类似如下的结果:

wKioL1mo-76SGnvdAABCUqArUeo708.png