一、简介

 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. 条款16:成对使用new和delete时要使用相同的形式

    请牢记: 如果在new表达式中使用[],必须在相应的delete表达式中也使用[]. new[]  对应  delete[] 如歌在new表达式中不适用[],一定不要在相应的delete表达式中使用[ ...

  2. 【maven 】jar包冲突-记一次冲突解决

    方法一:根据mvn提示一个一个排除 1.请到pom.xml文件所在的目录(包含父子目录)下分别执行下面的命令排查是什么原因导致fastjson版本不正确: mvn dependency:tree -D ...

  3. memcached--delete--replace--set--get--incr--decr--stats

    memcached命令 1.get  key 来获取在内存中的值 get name 2.delete  key 删除在内存中的值 delete name 3.replace  key flag exp ...

  4. memecached存放session数据

    memcached存放session 1.session数据需要频繁调用. 2.session数据不需要永久性的保存在服务端. 3.在集群中,可以将session存放在memcached中或者是在数据 ...

  5. visudo 与 /etc/sudoers

    增加多个用户免密码登录 User_Alias USER_OPS = zouyi,hanerhui,shibeibei,gaoxudong,xiaoyuelin,wangsongfeng,sunjian ...

  6. java Http工具类

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...

  7. HashMap源码分析(一):JDK源码分析系列

    正文开始 注:JDK版本为1.8 HashMap1.8和1.8之前的源码差别很大 目录 简介 数据结构 类结构 属性 构造方法 增加 删除 修改 总结 1.HashMap简介 HashMap基于哈希表 ...

  8. cur.execute(sql,args)和cur.execute(sql)的区别

    轉:https://blog.csdn.net/mjjyszazc/article/details/88932664 方式一: userid = “123”sql = “select id,name ...

  9. ETL-kettle 核心执行逻辑

    一.大数据下的ETL工具是否还使用Kettle kettle 作为通用的ETL工具,非常成熟,应用也很广泛,这里主要讲一下 目前我们如何使用kettle的? 在进行大数据处理时,ETL也是大数据处理的 ...

  10. nio原理和示例代码

    我正在为学习大数据打基础中,为了手撸rpc框架,需要懂得nio的原理,在搞懂nio框架前,我会带着大家手撸一些比较底层的代码,当然今后当我们学会了框架,这些繁琐的代码也就不用写了,但是学一学底层的代码 ...