一、简介

 Spring Cloud Confg 是用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端与客户端两个部分。其中服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密/解密信息等访问接口;而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。

二、Spring Config Server

搭建一个 Config Server,首先需要一个仓库,作为分布式配置中心的存储。这里我们选择了 Github 作为我们的仓库:https://github.com/JMCuixy/cloud-config-server/tree/master/config-repo

1. pom.xml

    <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>

2. application.yml

server:
port: 7001 spring:
application:
name: cloud-config-server # 配置完成后可访问的 url 如下,比如:http://localhost:7001/env/default
# /{application}/{profile} [/{label}]
# /{application}-{profile}.yml
# /{label}/{application}-{profile}.yml
# /{application}-{profile}.properties
# /{label}/{application}-{profile}.properties
cloud:
config:
# 为配置中心提供安全保护
username: user
password: password
server:
git:
# 仓库地址
uri: https://github.com/JMCuixy/cloud-config-server.git
# 搜索路径
search-paths: config-repo
# 访问 http://localhost:7001/actuator/health 可以获取配置中心健康指标
health:
repositories:
env:
name: env
profiles: default
label: master management:
endpoint:
health:
enabled: true
show-details: always eureka:
client:
service-url:
defaultZone: http://user:password@localhost:1111/eureka/

这里我没有配置 Github 的 username 和 password,用的是 SSH key 的方式。

3. ConfigApplication.java

// 开启 Spring Cloud Config 的 Server 功能
@EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigApplication { public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
} }

至此,一个 Spring Cloud Config Server 就搭建完成了。上面的配置中,我们将 Config Server 注册到 Eureka Server 中,当作整个系统服务的一部分,所以 Config Client 只要利用 Eureka 的服务发现维持与 Config Server 通信就可以了。

在Config Server 的文件系统中,每次客户端请求获取配置信息时,Confg Server 从 Git 仓库中获取最新配置到本地,然后在本地 Git 仓库中读取并返回。当远程仓库无法获取时,直接将本地内容返回。

三、Spring Config Client

Spring Cloud Confg 的客户端在启动的时候,默认会从工程的 classpath 中加载配置信息并启动应用。只有当我们配置 spring.cloud.config.uri(或者spring.cloud.config.discovery) 的时候,客户端应用才会尝试连接 Spring Cloud Confg 的服务端来获取远程配置信息并初始化 Spring 环境配置。同时,我们必须将该参数配置在bootstrap.yml、环境变量或是其他优先级高于应用 Jar 包内的配置信息中,才能正确加载到远程配置。

1. pom.xml

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency> <!-- 当连接 config-server 失败的时候,可增加重试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency> <!--配置动态刷新-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

2. bootstrap.yml 和 application.yml

  • bootstrap.yml
spring:
application:
# 对应配置文件规则中的 {application} 部分
name: env
cloud:
config:
name: env
# uri: http://localhost:7001
discovery:
enabled: true
service-id: cloud-config-server
# 环境变量
profile: default
# 分支
label: master
# config Server 配置的安全信息
username: user
password: password
# 快速失败响应(当发现 config-server 连接失败时,就不做连接的准备工作,直接返回失败)
fail-fast: true
# 失败重试
retry:
# 初始重试间隔时间,毫秒
initial-interval: 1000
# 下一间隔的乘数
multiplier: 1.1
# 最大间隔时间
max-interval: 2000
# 最多重试次数
max-attempts: 6

bootstrap 配置会系统会优先加载,加载优先级比 application 高。

  • application.yml
server:
port: 7002 spring:
application:
name: cloud-config-client eureka:
client:
service-url:
defaultZone: http://user:password@localhost:1111/eureka/ management:
endpoints:
web:
exposure:
# 开启指定端点
# 配置刷新地址:POST http://127.0.0.1:7002/actuator/refresh
include: 'refresh'

3. ConfigClientApplication.java

@EnableDiscoveryClient
@SpringBootApplication
public class ConfigClientApplication { public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
} }

4. 应用

接下来瞅瞅客户端要怎么读到服务器的配置项呢?

@RefreshScope
@RestController
public class ConfigClientAdmin { @Value("${from:default}")
private String from; @Autowired
private Environment environment; @RequestMapping("/from")
public String from() {
String fromEnv = environment.getProperty("from");
return from + "_" + fromEnv;
}
}

如上,我们可以使用 @Value 注解注入配置信息,或者使用 Environment Bean 来获取配置项。

需要注意的是,当服务端的配置项更新的时候,客户端并不会同步获得更新,需要 Post 方法执行 "/actuator/refresh" 来刷新配置项。

@RefreshScope 注解使配置的内容动态化,当使用 http://127.0.0.1:7002/actuator/refresh 刷新配置的时候,会刷新带有 @RefreshScope 的 Bean。

四、动态路由

上一篇文章 我们尝试用 Spring Cloud Zuul 搭建了网关服务,但是我们发现路由信息都配置在 application.yml 中,这对网关的高可用是个不小的打击,因为网关作为系统流量的路口,总不能因为改个路由信息天天重启网关吧?所以动态路由的实现,就变得迫不及待了,好在我们现在有了 Spring Cloud Config。

首先,我们将 Spring Cloud Zuul 的路由信息,配置在 Config Server 的 env.yml 中:

zuul:
routes:
client-1:
# ?:匹配任意单个数量字符;*:匹配任意多个数量字符;**:匹配任意多个数量字符,支持多级目录
# 使用 url 的配置没有线程隔离和断路器的自我保护功能,不推荐使用
path: /client-1/**
url: http://localhost:2222/
# 敏感头信息设置为空,表示不过滤敏感头信息,允许敏感头信息渗透到下游服务器
sensitiveHeaders: ""
customSensitiveHeaders: true
client-2:
path: /client-2/**
serviceId: cloud-eureka-client
# zuul.routes.<serviceid> = <path>
cloud-eureka-client: /client-3/**
client-4:
path: /client-4/**
# 请求转发 —— 仅限转发到本地接口
url: forward:/local # Zuul 将对所有的服务都不自动创建路由规则
ignored-services: "*"
# 对某些 url 设置不经过路由选择
ignored-patterns: {"/**/world/**","/**/zuul/**"}
# Spring Cloud Zuul在请求路由时,会过滤掉 HTTP 请求头(Cookie、Set-Cookie、Authorization)信息中的一些敏感信息,
sensitive-headers: {"Cookie", "Set-Cookie", "Authorization"}
# 网关在进行路由转发时为请求设置 Host 头信息(保持在路由转发过程中 host 头信息不变)
add-host-header: true
# 请求转发时加上 X-Forwarded-*头域
add-proxy-headers: true
# 是否开启重试,默认关闭
retryable: true
# 通过 /zuul 路径访问的请求会绕过 dispatcherServlet, 被 Zuu1Servlet 处理,主要用来应对处理大文件上传的情况。
servlet-path: /zuul
# 禁用某个过滤器 zuul.<SimpleClassName>.<filterTye>.disable=true
TokenFilter:
pre:
disable: true

然后,我们将网关服务注册为 Config Client(配置项与上面类似,就不赘述了),从 Config Server 获取路由信息:

@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class DynamicRouteApplication { public static void main(String[] args) {
SpringApplication.run(DynamicRouteApplication.class, args);
} /**
* 刷新地址:POST http://127.0.0.1:5006/actuator/refresh
* 路由查看地址:GET http://127.0.0.1:5006/actuator/routes
*
* @return
*/
@Bean
@Primary
//该注解来使 zuul 的配置内容动态化
@RefreshScope
@ConfigurationProperties(prefix = "zuul")
public ZuulProperties zuulProperties() {
return new ZuulProperties();
} }

这样,就把我们的路由信息交给 Config Server 去管理了~~

五、Spring Cloud Bus

上面的内容我们学习到:当 Config Server 配置变更了以后,Config Client 通过执行 “/actuator/refresh” 来刷新配置项。一两个实例的话,倒不算什么。实例一旦多了,这将是一个非常繁琐的工作。怎么办呢?就要说到 Spring Cloud Bus。

微服务架构的系统中,我们通常会使用轻量级的消息代理来构建一个共用的消息主题让系统中所有微服务实例都连接上来,由于该主题中产生的消息会被所有实例监听和消费,所以我们称它为消息总线。在总线上的各个实例都可以方便地广播一些需要让其他连接在该主题上的实例都知道的消息,例如配置信息的变更或者其他一些管理操作等。Bus 就是 Spring Cloud 中的消息总线。

那么 Spring Cloud Bus 怎么刷新我们的配置项呢?

  1. 当 Config Server 配置项发生变更的时候,发送一个消息到消息代理的 Topic 下。
  2. Config Client 订阅 Topic 接收到消息后,主动执行 “/actuator/refresh” 刷新配置。

Spring Cloud Bus 的集成(基于 RabbitMQ 消息代理)也非常简单,只需要我们在 Config Server 中引用:

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

然后,在 application.yml 中配置 RabbitMQ ,并暴露 “bus-refresh” 端点:

management:
endpoints:
web:
exposure:
# 执行 http://127.0.0.1:7001/actuator/bus-refresh,把配置内容修改的消息发布到服务总线。
# 客户端收到订阅消息,自动执行 /actuator/refresh,刷新配置
include: bus-refresh

客户端的配置和服务端类似,也只要引入 jar 包,配置 RabbitMQ 即可(不用暴露 “bus-refresh” 端点)。

篇幅有限,不细讲了,大家可以看我 GitHub 上的内容,包括 RabbitMQ 的集成和 Kafka 的集成。

六、附录

SpringBoot 版本号:2.1.6.RELEASE

SpringCloud 版本号:Greenwich.RELEASE

演示源代码 :https://github.com/JMCuixy/spring-cloud-demo

内容参考:《Spring Cloud 微服务实战》

Spring Cloud 之 Config与动态路由.的更多相关文章

  1. Spring Cloud gateway 网关四 动态路由

    微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...

  2. spring cloud 2.x版本 Zuul路由网关教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka ...

  3. spring cloud 2.x版本 Gateway路由网关教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前两篇文章eureka-server.eureka-client.eureka ...

  4. Spring Cloud 整合 nacos 实现动态配置中心

    上一篇文章讲解了Spring Cloud 整合 nacos 实现服务注册与发现,nacos除了有服务注册与发现的功能,还有提供动态配置服务的功能.本文主要讲解Spring Cloud 整合nacos实 ...

  5. Alibaba Nacos 学习(二):Spring Cloud Nacos Config

    Alibaba Nacos 学习(一):Nacos介绍与安装 Alibaba Nacos 学习(二):Spring Cloud Nacos Config Alibaba Nacos 学习(三):Spr ...

  6. Spring Cloud Consul Config 知识点

    Spring Cloud Consul Config 是 Config Server 和 Client的替代方案. 搭建一个配置中心,可以选择的方案: Spring Cloud Config 或者 S ...

  7. Spring Cloud (十三) Zuul:静态路由、静态过滤器与动态路由的实现

    前言 本文起笔于2018-06-26周二,接了一个这周要完成的开发任务,需要先等其他人的接口,可能更新的会慢一些,还望大家见谅.这篇博客我们主要讲Spring Cloud Zuul.项目地址:我的gi ...

  8. Spring Cloud Gateway 扩展支持动态限流

    之前分享过 一篇 <Spring Cloud Gateway 原生的接口限流该怎么玩>, 核心是依赖Spring Cloud Gateway 默认提供的限流过滤器来实现 原生Request ...

  9. Spring Boot系列(四) Spring Cloud 之 Config Client

    Config 是通过 PropertySource 提供. 这节的内容主要是探讨配置, 特别是 PropertySource 的加载机制. Spring Cloud 技术体系 分布式配置 服务注册/发 ...

随机推荐

  1. Java基础(二) 基本类型数据类型、包装类及自动拆装箱

    我们知道基本数据类型包括byte, short, int, long, float, double, char, boolean,对应的包装类分别是Byte, Short, Integer, Long ...

  2. hadoop之hbase基本操作

    hbase shell 进入hbase命令行 list 显示HBASE表 status 系统上运行的服务器的细节和系统的状态 version 返回HBase系统使用的版本 table_help 引导如 ...

  3. play框架之简介

    Play Framework是一个开源的Web框架,背后商业公司是Typesafe.要介绍Play之前,首先理清Play的两个不同的分支. Play 1.x 使用Java开发,最新版本是1.3.1,只 ...

  4. Linux上整数和浮点数的运算

    一:shell中对整数和浮点数的运算     常用的运算符号         加法+    减法 -     乘法*     除法/     求余%              +=        -= ...

  5. python-基本数据类型(int,bool,str)

    一.python基本数据类型 1. int ==>  整数. 主要⽤用来进⾏行行数学运算 2. str ==> 字符串串, 可以保存少量量数据并进⾏行行相应的操作 3. bool==> ...

  6. l论文查重平台

    推荐大家一个靠谱的论文检测平台.重复的部分有详细出处以及具体修改意见,能直接在文章上做修改,全部改完一键下载就搞定了.怕麻烦的话,还能用它自带的降重功能.哦对了,他们现在正在做毕业季活动, 赠送很多免 ...

  7. 关于Jvm类加载机制,这一篇就够了

    前言 一个月没更新了,这个月发生了太多的事情,导致更新的频率大大降低,不管怎样收拾心情,技术的研究不能落下! jvm作为每个java程序猿必须了解的知识,博主推荐一本书<深入理解Java虚拟机& ...

  8. 使用事件注册器进行swoole代码封装

    在使用swoole的时候,事件回调很难维护与编写,写起来很乱.特别在封装一些代码的时候,使用这种注册,先注册用户自己定义的,然后注册些默认的事件函数. Server.php class Server ...

  9. JAVA复习笔记02

    16.interface中的成员变量默认为public static final类型,方法只能是public(默认为public) 17.内部类访问外部类成员: Outer.this.num; 18. ...

  10. 关于重写equals()和hashCode()的思考

    最近这几天一直对equals()和hashCode()的事搞不清楚,云里雾里的. 为什么重写equals(),我知道. 但是为什么要两个都要重写呢,我就有点迷糊了,所以趁现在思考清楚后记录一下. 起因 ...