结合Spring Cloud Bus实现配置动态刷新
在上一节中我们学习了在Spring Cloud微服务系统架构中使用Config Server进行本地仓库配置读取和线上环境的远程仓库git配置读取,让我们在多个微服务下也可以进行配置信息的集中管理。但是还有一个问题,那就是Config Server从git读取配置文件是项目启动的时候进行的,如果项目启动后我们修改了配置信息,那么服务还是使用原来的配置信息,想要修改的配置即时生效我们还需要重启服务项目进行手动刷新。为了解决这个问题,Spring Cloud提供了一些解决方式,例如,提供@RefreshScope注解可以实现配置修改之后自动刷新、提供Spring Cloud Bus消息总线配合Config Server进行多端配置的自动刷新。下面我们就来看看如何在Spring Cloud系统中实现配置的自动刷新。
1. 使用@RefreshScope实现配置刷新 在使用@RefreshScope之前我们先了解下这个注解。
对于@RefreshScope注解,官方是这样解释的:在被此注解修饰的范围中的所有Bean仅在首次访问时初始化,因此该范围强制使用延迟初始化(延迟加载)。
这个注解会为涉及作用域中的每个Bean创建一个代理对象。
如果一个Bean被刷新,那么下次访问该Bean(即执行一个方法)时,就会创建一个新实例。
所有生命周期方法都应用于Bean实例,因此在刷新时会调用在Bean工厂的销毁回调方法,然后在创建新实例时正常调用初始化回调,新的Bean实例是根据原始Bean定义创建的,因此任何外部化的内容(属性占位符或字符串文本中的表达式)在创建时都会重新计算。
上面的描述说明了该注解的工作原理,具体实现配置自动刷新的代码参考RefreshScope类、GenericScope类以及Scope接口的代码即可,这里就不展示了。
在Spring Cloud 2.0之前,我们只需要加入Actuator依赖,然后在使用的地方加上@RefreshScope注解就可以使用Spring Cloud 暴露的接口“/refresh”来刷新配置。
但是Spring Cloud 2.0之后,需要我们主动暴露Actuator的端点才可以。
接下来我们通过一个案例来使用@RefreshScope,具体步骤如下。
① 在服务config-client的pom.xml文件中加入Actuator依赖,如程序清单14-10所示。
并在使用配置的地方添加@RefreshScope注解,如程序清单14-11所示。
② 在application.yml或bootstrap.yml中,暴露Actuator的“refresh”端点信息,如程序清单14-12所示。
③ 进行测试。我们依次启动项目eureka-server、config-server、config-client。先在浏览器中访问“http://localhost:7031/config/getVersion”,查看配置信息,如图所示。
然后在远程git上修改配置信息mylog的version为V3.0.0,并通过Postman等工具使用POST请求访问“/actuator/refresh”,如图所示。
我们再次在浏览器中访问“http://localhost:7031/config/getVersion”,可以发现配置信息已经更新,如图所示。
然后在远程git上修改配置信息mylog的version为V3.0.0,并通过Postman等工具使用POST请求访问“/actuator/refresh”,如图所示。
然后在远程git上修改配置信息mylog的version为V3.0.0,并通过Postman等工具使用POST请求访问“/actuator/refresh”,如图所示。
我们发现使用@RefreshScope注解之后,不需要重启项目就可以从git获取最新配置,但是目前还是存在两个问题。
问题一:需要我们使用Postman等工具手动调用POST请求接口“/actuator/refresh”才能刷新配置。
问题二:每次调用/actuator/refresh接口只能通知一个Config Client进行刷新,要刷新所有的Config Client就需要一个一个地调用。
问题一的解决方法:手动调用接口来刷新的问题,我们可以很容易地解决,因为不管是开源的GitHub和Gitee还是自建的GitLab都提供了“WebHook”功能。
WebHook可以在我们修改git的文件的时候触发一个行为帮我们调用一个接口,这样就很好地解决了手动刷新的问题。
WebHook功能和WebHook功能参数配置如图所示。
URL就是前面提到的刷新配置的地址“http://localhost:7031/actuator/refresh”,但是必须保证这个地址是可以被GitHub访问到的。也就是说,如果想使用本地项目内网的运行环境就不能使用GitHub或者Gitee的WebHook功能,当然,如果在本地项目内网搭建了代码管理工具(例如自建的GitLab),就可以调用到内网的地址。 问题二的解决方法:多端配置刷新需要我们结合Spring Cloud为我们提供的另外一个组件Spring Cloud Bus来实现,具体内容见下一小节。
2、使用Spring Cloud Bus实现多端配置刷新
SpringCloud Bus将分布式系统的节点与轻量级消息代理连接起来。
Spring Cloud Bus可以用于广播状态更改(如配置更改)或其他管理指令。
Spring Cloud Bus就像一个扩展的Spring Boot 应用程序的分布式执行器,但也可以用作应用程序之间的通信渠道。
Spring Cloud Bus核心原理是利用基于AMQP(Advanced Message Queuing Protocol,高级消息队列协议)的消息队列做广播来传播配置更新的消息,然后接收到消息的所有Config Client会从Config Server重新获取配置并刷新配置。
结合Spring Cloud Bus实现自动刷新的流程如图所示。目前官方支持RabbitMQ和Kafka。
在刷新配置的时候使用“/actuator/refresh”接口可以单独刷新一个微服务(局部刷新),而使用“/actuator/bus-refresh”接口则可以刷新所有的config-client端配置(全局刷新)。
接下来我们以RabbitMQ为例,使用Spring Cloud Bus实现多端配置刷新,开发步骤如下。
① 安装RabbitMQ,这里我们介绍Windows环境的RabbitMQ安装。
在安装RabbitMQ之前我们首先需要在计算机上安装Erlang,原因是RabbitMQ服务端代码是使用并发式语言Erlang编写的。
进入Erlang下载页面后选择Windows版本,如图所示。
下载好之后直接双击EXE文件进行安装即可。安装完之后配置Erlang的环境变量,如图所示。
然后进入RabbitMQ下载页面下载Windows版本的RabbitMQ,如图所示。
下载完成之后安装RabbitMQ。这里值得注意的是,RabbitMQ和Erlang的版本一定要兼容,兼容版本参考如图所示。
② 安装好RabbitMQ之后我们需要启用插件管理。
RabbitMQ的安装包默认是没有启用任何插件的,所以我们需要使用cmd并运行命令来启用RabbitMQ插件管理。
我们可以进入RabbitMQ安装目录,并进入其sbin目录,打开cmd命令行窗口,然后输入命令“rabbitmq-plugins. bat enable rabbitmq_management”启用插件,如图所示。
③ 在开始菜单中找到并启动RabbitMQ服务,如图所示。
然后在浏览器中访问“http://localhost:15672/”,会弹出RabbitMQ后台登录页面,如图所示。
输入默认的用户名和密码(guest/guest)即可进入后台管理页面进行消息队列管理,如图所示。
④ 对之前的服务config-server进行修改,在服务的pom.xml文件中加入Spring Cloud Bus依赖和Actuator依赖,如程序清单14-13所示。
然后在application-pro.yml文件中配置Actuator暴露端点、启用Spring Cloud Bus以及RabbitMQ连接信息,如程序清单14-14所示。
⑥ 功能测试。先配置两个端口号不一样的config-client和config-client2,如图所示。
然后启动各个服务,之后将git仓库中配置文件版本修改为“V3.1.0”,然后使用Postman的POST请求方式访问“http://localhost:7030/actuator/bus-refresh”刷新配置,如图所示。
分别访问“http://localhost:7031/config/getVersion”和“http://localhost:7032/config/getVersion”,发现配置已经刷新,证明我们使用Spring Cloud Bus完成了多端配置刷新,如图所示。
同样地,我们也可以查看RabbitMQ的队列信息、消息发送和接收情况等,如图所示。