1、概述
微服务架构意味着将会产生越来越多的单体服务,每个业务模块都被拆成了一个微服务模块,每个微服务模块中,都有各自的配置文件,随着模块的增多,配置文件越来越多,因此,需要有一个集中式的、动态配置的管理来解决这个问题。于是Spring Cloud
提供了Config
类解决这个问题,它为微服务中的模块提供集中化的外部配置支持
,配置服务器为各个不同微服务应用
的所有环境提供一个中心化的外部配置
。
Spring Cloud Config
分为服务端
和客户端
两部分。
服务端称为分布式配置中心
,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口。
客户端通过指定配置中心来管理应用资源以及与业务相关的配置内容
,在启动的时候,从配置中心读取加载配置信息,配置服务器默认采用git
来存储配置信息,有助于对环境配置进行版本管理,可以通过git
客户端工具方便管理和访问配置内容。
Config
的功能:
- 集中管理配置文件
- 不同环境可以使用不同的配置,动态配置更新
- 运行期间,动态调整配置,不再需要在每个服务部署的机器上修改配置文件,服务回向配置中心统一拉取配置信息
- 当配置发生变化,服务不需要重启即可感知到配置的变化,并应用新的配置
- 将配置信息以
REST
接口形式暴露
2、Config服务端配置与测试
在自己账号GitHub
或者Gitee
上新建一个springcloudconfig2020
的仓库,把自己本地的代码push
上去,此时本地仓库和远程仓库就建立联系了。
添加cloud-config-center-3344
模块,修改pom.xml
,添加spring-cloud-config-server
服务端依赖。
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<!-- 引入父级模块名称 -->
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.king.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 子模块名称 -->
<artifactId>cloud-config-center-3344</artifactId>
<dependencies>
<!-- 引入spring cloud config服务端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 引用eureka-client注册服务客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引用cloud-api-common公共模块 -->
<dependency>
<groupId>com.king.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 引用父级spring boot的依赖 -->
<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.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 引用父级的lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
cloud-config-center-3344
模块添加application.yml
配置文件。
# 配置服务端口号
server:
port: 3344
# 配置应用信息
spring:
application:
name: cloud-config-client # 配置应用名称
cloud:
# Config客户端配置
config:
server:
git:
# uri: https://gitee.com/xxx/springcloudconfig2020.git # Github上的仓库地址
uri: git@gitee.com:xxx/springcloudconfig2020.git #设置git仓库地址 # Github上的仓库地址
search-paths: # 搜索目录,即配置文件的目录
- springcloudconfig2020
label: master # 分支名称
# 配置eureka
eureka:
client:
service-url:
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/
cloud-config-center-3344
模块添加主启动类,使用注解@EnableConfigServer
激活配置中心。
package com.king.springcloud.com.king.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* @EnableConfigServer:开启SpringCloudConfig配置
*/
@EnableConfigServer
@SpringBootApplication
public class ConfigCenterMain3344 {
public static void main(String[] args) {
SpringApplication.run(ConfigCenterMain3344.class, args);
}
}
先说一下url
地址构造规则,通过官方文档的Quick Start可知,访问路径有如下5
种形式:
label:分支(branch)
application:文件名前缀
profile:文件名后缀,环境(dev/test/prod)
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
启动cloud-eureka-server7001
注册中心模块,启动配置中心模块,在控制台可以看到如下内容,来到这个文件夹,可以看到和GitHub/Gitee
地址相同的内容,表明配置中心在启动的时候,会把GitHub/Gitee
地址的内容拉下来一份,作为缓存,防止每次都从GitHub/Gitee
*问速度慢的问题。
2021-10-09 14:13:43.281 INFO 39724 --- [nio-3344-exec-1] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/m9/syz58y4n54bbtc03jbdx8qth0000gp/T/config-repo-6117864259229222371/config-dev.yml
2021-10-09 14:22:13.021 INFO 39724 --- [nio-3344-exec-4] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/m9/syz58y4n54bbtc03jbdx8qth0000gp/T/config-repo-6117864259229222371/config-test.yml
2021-10-09 14:22:33.164 INFO 39724 --- [nio-3344-exec-5] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/m9/syz58y4n54bbtc03jbdx8qth0000gp/T/config-repo-6117864259229222371/config-prod.yml
这时候,我们通过浏览器访问http://localhost:3344/master/config-prod.yml
,发现页面上显示出了config-dev.yml
的内容。在GitHub/Gitee
上,将config-dev.yml
的内容做一下简单的改动并提交,无需重启配置中心模块,再次通过浏览器访问http://localhost:3344/master/config-dev.yml
,浏览器上展示的内容是我们修改后的,在控制台可以看到类似的info
输出,回到本地缓存文件夹,对比config-dev.yml
的修改日期和其他配置文件的修改日期,只有config-dev.yml
的日期时间是最新的,其他的配置文件还是配置中心启动时候的日期时间。
所以,当我们给配置中心发送一个获取配置文件请求的时候时,配置中心先去看下GitHub/Gitee
地址有没有最新的提交记录,如果有,先pull
下来,覆盖本地缓存,再响应请求,如果没有,直接把本地缓存的内容作为响应。
3、Config客户端配置与测试
新建cloud-config-client-3355
模块,修改pom.xml
,添加spring-cloud-starter-config
客户端依赖。
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<!-- 引入父级模块名称 -->
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.king.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 子模块名称 -->
<artifactId>cloud-config-client-3355</artifactId>
<dependencies>
<!-- 引入spring cloud config客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 引用eureka-client注册服务客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引用cloud-api-common公共模块 -->
<dependency>
<groupId>com.king.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 引用父级spring boot的依赖 -->
<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.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 引用父级的lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
在创建cloud-config-client-3355
模块application.yml
配置文件之前,先说一个知识点。
Spring Boo
t默认是支持*.properties
和*.yml
配置文件的,使用Spring Boot
构建Spring Cloud
应用的时候,Spring Boot
有两种上下文环境
,一个是Bootstrap
,一个是Application
,当application.yml
和bootstrap.yml
在同一目录下的时候,bootstrap.yml先加载
,application.yml后加载
,Bootstrap Context
是Application Context
的父级上下文
。初始化的时候,Bootstrap Context负责从外部配置文件中加载配置文件
,bootstrap.yml
是系统级别的,Application Context负责应用内部加载配置文件
,application.yml
是用户级别的。因为bootstrap.yml
的级别高于application.yml
,所以,bootstrap.yml
的配置不会被application.yml
所覆盖。对于一个Spring Boot
模块,此时,它的配置文件来源可能有两个,一个是bootstrap.yml
,一个是application.yml(
当然,也可以没有application.yml
,只走bootstrap.yml
如果能满足需求也行)。
因为要读取配置中心的配置信息,所以这里使用bootstrap.yml
,cloud-config-client-3355
模块添加bootstrap.yml
。
# 配置服务端口号
server:
port: 3355
# 配置应用信息
spring:
application:
name: cloud-config-client # 配置应用名称
cloud:
# Config客户端配置
config:
label: master # 分支名称
name: config # 配置文件前缀名称
profile: dev # 读取后缀名称
uri: http://localhost:3344 # 上诉3个综合就是master分支上config-dev.yml,读取目标资源路径,这里读取cloud-config-center-3344模块
# 配置eureka
eureka:
client:
service-url:
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/
cloud-config-client-3355
模块添加主启动类。
package com.king.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355 {
public static void main(String[] args) {
SpringApplication.run(ConfigClientMain3355.class, args);
}
}
cloud-config-client-3355
模块添加业务类,用于验证客户端是否真的从配置中心拿到配置信息了。
package com.king.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigClientController {
// 因为config仓库以rest形式暴露,所以客户端可以通过config服务端访问到GitHub上对应的文件信息
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
启动cloud-eureka-server7001
模块、cloud-config-client-3344
模块、cloud-config-client-3355
模块,浏览器访问http://localhost:3355/configInfo
,可以拿到cloud-config-center-3344
模块下config-dev.yml
的配置,这里我们读取config.info
属性的值。
在GitHub/Gitee
上直接修改config-dev.yml
的内容,直接访问配置中心http://localhost:3344/master/config-dev.yml
改动立刻生效,访问http://localhost:3355/configInfo
改动并没有更新,重启cloud-config-client-3355
模块后,再次访问生效了,可是这并不是最好的方式,因为重启服务代价太大了
。
重启cloud-config-client-3355
模块后:
4、Config客户端之动态刷新
为了避免每次都重启cloud-config-client-3355
服务,现在要实现cloud-config-client-3355
的动态刷新。修改cloud-config-client-3355
的pom.xml
,添加spring-boot-starter-actuator
健康监控依赖。修改 bootstrap.yml
,暴露所有监控端点,默认情况下,访问http://localhost:3355/actuator
只会暴露部分端点,使用"*"
让actuator
把所有端点都暴露出来。
修改cloud-config-client-3355
模块bootstrap.yml
文件:
# 配置服务端口号
server:
port: 3355
# 配置应用信息
spring:
application:
name: cloud-config-client # 配置应用名称
cloud:
# Config客户端配置
config:
label: master # 分支名称
name: config # 配置文件前缀名称
profile: dev # 读取后缀名称
uri: http://localhost:3344 # 上诉3个综合就是master分支上config-dev.yml,读取目标资源路径,这里读取cloud-config-center-3344模块
# 配置eureka
eureka:
client:
service-url:
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/
# 暴露所有监控端点
management:
endpoints:
web:
exposure:
include: "*"
在cloud-config-client-3355
模块的业务类( ConfigClientController
)上添加@RefreshScope
注解(用来实现动态配置、实例热加载)。
package com.king.springcloud.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;
/**
* 用来实现动态配置、实例热加载
*/
@RefreshScope
@RestController
public class ConfigClientController {
// 因为config仓库以rest形式暴露,所以客户端可以通过config服务端访问到GitHub上对应的文件信息
@Value("${config.info}")
private String configInfo;
@GetMapping("/configInfo")
public String getConfigInfo() {
return configInfo;
}
}
重启cloud-config-client-3355
模块,在GitHub/Gitee
上修改config-dev.yml
的内容。访问http://localhost:3344/master/config-dev.yml
可以看到配置信息随之修改,访问http://localhost:3355/configInfo
发现配置信息并没有改变
,此时我们还需要一步操作
:cmd
中通过curl发送一个post形式的refresh请求给3355
,再次访问http://localhost:3355/configInfo
,即可拿到最新的配置信息了,避免了3355
服务的重启。
test-MBP:~ test$
curl -X POST "http://localhost:3355/actuator/refresh"
[“config.client.version”,“config.info”]test-MBP:~ test$
其实这种方式还是有缺陷的,如果有非常多的微服务客户端,每一个都去发送请求执行刷新,也是很麻烦的,下面我们引入Spring Cloud Bus
消息总线,采用广播的形式,一旦配置中心的配置发生变更,监听配置中心的各个微服务客户端就能收到消息,于是,refresh操作就可以自动完成了。