- 前言
在需在微服务客户端添加以下依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
提供了/refresh端点用于配置的刷新。当配置修改了
每个微服务只需运行http://ip:port/refresh 就会刷新配置
(通过webhook运行)
思考:
上面使用/refresh端点手动刷新配置,但如果所有微服务客户端的配置都需要手动去刷新,工作量是很大的。
那么,我们也可以利用webhook的机制每次提交代码发送请求刷新微服客户端,当服务越来越多,需要每个客户端都执行,这样就不合适了。
随着系统的不断扩展会越来越难维护。消息代理是解决该问题最为合适的方案。消息代理中间件可以将消息路由到一个或多个
目的地。
- Spring Cloud Bus
Spring Cloud Bus使用轻量级的消息消息代理(RabbitMQ Kafka)连接分布式系统的节点,这样就可以广播传播状态的更改(如配置的更改)
第一种通过刷新微服务端点获取配置中心最新配置
大体思路如下图,webHook也可以用postman代替
根据此图我们可以看出利用Spring Cloud Bus做配置更新的步骤:
1、提交代码触发post给客户端A发送bus/refresh
2、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus
3、Spring Cloud bus接到消息并通知给其它客户端
4、其它客户端接收到通知,请求Server端获取最新配置
5、全部客户端均获取到最新的配置
演示
Config-Client
1.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>2.spring-cloud-service-provide</groupId> <artifactId>service-provide</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>spring-cloud Maven Webapp</name> <url>http://maven.apache.org</url> <!--springboot采用1.5.x 对应springcloud版本为 Dalston --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!--@SpringCloudApplication注解需要依赖的 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--用于动态刷新配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!--失败重试 --> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--消息总线 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 这样变成可执行的jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
2,配置文件
application.properties
#配置端口 server.port=8082 |
bootstrap.properties
#指定注册中心 eureka.client.serviceUrl.defaultZone=http://testhost:8000/eureka/,http://testhost2:8001/eureka/ #开起通过服务来访问Config Server spring.cloud.config.discovery.enabled=true #指定配置分布式配置中心服务名 spring.cloud.config.discovery.serviceId=config-server #指定git仓库的分支,对应config server所获取的配置文件的{label} spring.cloud.config.label=master #失败快速响应和重试 spring.cloud.config.failFast=true #对应 config server所获取的配置文件的{application} spring.application.name=niugang #对应config server所获取的配置文的{profile} spring.cloud.config.profile=dev #http://localhost:8082/bus/refresh 挂到总线上的客户端都从注册中心 干掉了 这是bug #<spring-cloud.version>Dalston.SR1</spring-cloud.version> #消息代理地址 |
3.测试类
package com.niugang.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController /** * * 在refresh作用域中放置@Bean定义的便利注释。以这种方式注释的bean可以在运行时刷新,使用它们的任何组件将在下一个方法调用中获得一个新实例,完全初始化并注入所有依赖项。 * */ @RefreshScope //必须加这个注解,否则通过消息总线从git上已经更新了最新到配置到本地仓库,但是代码运行时拿不到最新的配置 public class ConfigClientController { /** * 从niugang-dev.properties中获取配置的from值 */ @Value("${from}") private String from; @RequestMapping("/profile") public String profile() { return this.from; } } |
config-server配置
#指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问 spring.application.name=config-server server.port=8779 # 配置服务注册中心 #注册中心地址 eureka.client.serviceUrl.defaultZone=http://testhost:8000/eureka/,http://testhost2:8001/eureka/ #指定本地仓库路径,默认是随机生成 spring.cloud.config.server.git.basedir=/home/springcloud/configrepos # git仓库配置 主分支路径 spring.cloud.config.server.git.uri=https://gitee.com/niugangxy/springcloud spring.cloud.config.server.git.force-pull=true #很多场景下,可能把配置文件放在git仓库子目录下,可通过searchPaths配置,searchPaths也支持占位符 #如下配置,Config server会在git目录spring-cloud-config-respo,及其子目录下查找配置文件 spring.cloud.config.server.git.searchPaths=spring-cloud-config-respo #git用户名 spring.cloud.config.server.git.username=xxxxx #git用户密码 spring.cloud.config.server.git.password=xxxxxxx |
分别启动注册中心,config-server,config-client.
先分别测试一下服务端和客户端是否正确运行,访问:http://localhost:8779/niugang/dev,返回信息:
{"name":"niugang","profiles":["dev"],"label":null,"version":null,"state":null,"propertySources":[{"name":"https://gitee.com/niugangxy/springcloud/spring-cloud-config-respo/niugang-dev.properties","source":{"from":"git-dev-7.0"}},{"name":"https://gitee.com/niugangxy/springcloud/spring-cloud-config-respo/niugang.properties","source":{"from":"git-default-1.0"}}]} |
说明服务端正常。
依次访问http://localhost:8081/profile,http://localhost:8082/profile 返回git-dev-9.0
然后更新niugang-dev.properties 中git-dev-9.0的值为git-dev-10.0并提交到代码库中,访问:http://localhost:8081/profile 依然返回git-dev-9.0。我们对端口为8082的客户端发送一个/bus/refresh的post请求,更新到最新的配置,发送过程中可以看项目打印日志.(使用postman也可以直接在git的webhook中设置)。
然后在依次访问http://localhost:8081/profile,http://localhost:8082/profile 则返回git-dev-10.0
第二种通过刷新Config-Server端点获取配置中心最新配置
在上面的演示例子中,通过请求某个微服务/bus/refresh端点的方式来实现配置的刷新,但这并不优雅灰更加运维的工作。原因如下:- 打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。
- 破坏了微服务各节点的对等性。
- 有一定的局限性。例如,微服务在迁移时,它的网络地址常常会发生变化,此时如果想要做到自动刷新,那就不得不修改WebHook的配置。
Config-Server
1.pom.xml
增加如下配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>2.spring-cloud-service-provide</groupId> <artifactId>service-provide</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>spring-cloud Maven Webapp</name> <url>http://maven.apache.org</url> <!--springboot采用1.5.x 对应springcloud版本为 Dalston --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <!--将微服务注册到注册中心 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <!--@SpringCloudApplication注解需要依赖的 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--消息总线 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 这样变成可执行的jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
2.application.properties配置
#指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问 spring.application.name=config-server server.port=8779 # 配置服务注册中心 #注册中心地址 eureka.client.serviceUrl.defaultZone=http://testhost:8000/eureka/,http://testhost2:8001/eureka/ #指定本地仓库路径,默认是随机生成 spring.cloud.config.server.git.basedir=/home/springcloud/configrepos # git仓库配置 主分支路径 spring.cloud.config.server.git.uri=https://gitee.com/niugangxy/springcloud spring.cloud.config.server.git.force-pull=true #很多场景下,可能把配置文件放在git仓库子目录下,可通过searchPaths配置,searchPaths也支持占位符 #如下配置,Config server会在git目录spring-cloud-config-respo,及其子目录下查找配置文件 spring.cloud.config.server.git.searchPaths=spring-cloud-config-respo #git用户名 [email protected] #git用户密码 spring.cloud.config.server.git.password=niu85848116 #消息代理地址 spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=springcloud spring.rabbitmq.password=123456 #取消bus/refresh发送post请求 需要认证,刷新是关闭验证 management.security.enabled=false spring.cloud.bus.trace.enabled=true |
启动注册中心,启动最新配置的Config-Server,启动两个Config-Client(带RabbitMQ配置的,配置如上不变).进行验证。
postman发送的http请求:
http://localhost:8779/bus/refresh