1.前言
在本文,我们将构建一个基于 Git 版存储的分布式配置中心,并对客户端进行改造,其能够从远程配置中心获取配置信息,并绑定到代码中的 Spring Cloud Config 配置中心模块。
Spring Cloud Config
- Spring Cloud 团队创建的一个全新项目
- 用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端与客户端两个部分
- 实现了对服务端和客户端中环境变量和属性配置的抽象映射,所以它除了适用于 Spring 构建的应用程序之外,也可以在任何其他语言运行的应用程序中使用
- 默认采用 Git 来存储配置信息,所以也支持对微服务应用配置信息的版本管理,并且可以通过 Git 客户端工具来方便的管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如:SVN 仓库、本地化文件系统
配置中心服务端:
服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密 / 解密信息等访问接口
配置中心客户端:
客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息
上一节:SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
2.准备
- 服务注册中心:wei-eureka-server,端口号:8090(无需修改,正常启动)
- 服务提供者:wei-service-provider,端口号:8010、8011(以端口号正常启动)
- 远程配置文件(本节新建)
- Config Server:wei-config-server ,端口号:8050(本节新建)
- Config Client:wei-config-client ,端口号:8060(本节新建)
先准备一份远程配置文件。这里参考公开仓库 https://github.com/itanping/wei-springcloud 下 wei-config/config-profile 目录,里面有以下三个配置文件:
![](https://i-blog.csdnimg.cn/blog_migrate/e6b03643af570fd37e52e1189abd70fb.png)
其开发环境:config-client-dev.properties 配置如下:
config.env=dev
config.tip=Demo for Spring Cloud config
其测试环境:config-client-test.properties 配置如下:
config.env=test
config.tip=Demo for Spring Cloud config
其生产环境:config-client-prod.properties 配置如下:
config.env=prod
config.tip=Demo for Spring Cloud config
三个环境配置文件的属性基本一样,config.env 属性值分别是 dev、test、prod。
3.进击
3.1.服务端(Config Service)
在项目上新建一个模块:wei-config-server。
创建方法与 第一节 创建模块过程类似。但在Dependencies选择依赖时需要注意,选择左侧的 Cloud Config 后,这里需要钩上 Config Server 项。
![](https://i-blog.csdnimg.cn/blog_migrate/c4a3a39cf2ce9d012e65adf38814a64d.png)
3.1.1.pom.xml依赖
pom依赖自动生成后,不用变动。
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wei</groupId>
<artifactId>wei-config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wei-config-server</name>
<description>Demo project for Spring Cloud Config</description>
<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>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.1.2.配置文件
在 application.yml 中添加配置服务的基本信息以及 Git 仓库的相关信息。
server:
port: 8050
spring:
application:
name: wei-config-server
cloud:
config:
label: master # 对应 Git 上不同的分支,默认为 master
server:
git:
username:
password:
uri: https://github.com/itanping/wei-springcloud # 配置 Git 仓库地址
search-paths: wei-config/config-profile # Git仓库地址下的相对地址,可以配置多个,用,分割
如果 Git 仓库需要权限访问,则需要配置下面的两个属性来实现(如果 Git 仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写,示例代码为公开仓库,这里配置了属性项,但可以不用设置密码):
- spring.cloud.config.server.git.username:访问 Git 仓库的用户名
- spring.cloud.config.server.git.password:访问 Git 仓库的用户密码
3.1.3.启动类
在该模块的启动类上加上注解@EnableConfigServer,开启对配置中心的支持。
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
/**
* Config Server
* 注解@EnableConfigServer,开启对配置中心的支持
*/
@SpringBootApplication
@EnableConfigServer
public class WeiConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(WeiConfigServerApplication.class, args);
}
}
好了,到此,Spring Cloud Config Server 服务端的相关配置已经完成。
3.1.4.测试
启动模块 wei-config-server 的启动类 WeiConfigServerApplication。
访问开发环境:http://localhost:8050/config-client/dev,浏览器打印信息:
![](https://i-blog.csdnimg.cn/blog_migrate/54b2dcdf67c552c31562fe2d5af8c499.png)
{
"name": "config-client",
"profiles": [
"dev"
],
"label": null,
"version": "9f1e2980b3619b18d1f0de3b416f7e5ea4fde804",
"state": null,
"propertySources": [
{
"name": "https://github.com/itanping/wei-springcloud/wei-config/config-profile/config-client-dev.properties",
"source": {
"config.env": "dev",
"config.tip": "Demo for Spring Cloud config"
}
}
]
}
上面返回的信息包含了配置文件的名称、位置、版本,以及配置文件中的具体内容,说明 Config Server 端已经成功获取到了 Git 仓库的配置信息。
请求测试环境:http://localhost:8050/config-client/test
![](https://i-blog.csdnimg.cn/blog_migrate/fb331df740801356b55e85e506e4a060.png)
浏览器正常打印了测试环境的配置文件内容。试试生产环境,你会发现同样的也会打印生产环境的配置文件内容。
3.1.5.动态更新
修改配置文件 config-client-dev.properties 中的属性为 config.env=dev for update,以实现 Git 存储与动态更新的读取,如下:
config.env=dev
config.tip=Demo for Spring Cloud config 2018-12-25
再次请求开发环境:http://localhost:8050/config-client/dev
{"name":"config-client","profiles":["dev"],"label":null,"version":"58195d6f7f1b4c86f10619f00ae36d2718a6d856","state":null,"propertySources":[{"name":"https://github.com/itanping/wei-springcloud/wei-config/config-profile/config-client-dev.properties","source":{"config.env":"dev","config.tip":"Demo for Spring Cloud config 2018-12-25"}}]}
可以看到浏览器打印了更新后的开发环境配置内容,说明 Config Server 端会自动动态读取 Git 最新提交的内容。
因为服务端的 pom 核心依赖 spring-cloud-config-server 已经默认加载了 spring-boot-starter-actuator。
如此,Config Server 配置服务中心已经可以正常运作。
3.2.客户端(Config Client)
在项目上新建一个模块:wei-config-client。
创建方法与第一节创建模块过程类似。但在Dependencies选择依赖时需要注意,选择左侧的 Cloud Config 后,这里需要钩上 Config Client 项。
3.2.1.pom.xml依赖
也是自动生成的 pom 依赖,这里先不做修改。
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wei</groupId>
<artifactId>wei-config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wei-config-client</name>
<description>Demo project for Spring Cloud Config</description>
<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>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2.2.配置文件
如何在微服务应用中获取上面服务端提供的配置信息呢?
这里我们新加一个配置文件 bootstrap.yml。注意,一般情况下,application.yml 和 bootStrap.yml 在同一目录下,这时 bootStrap.yml 的加载顺序要高于 application.yml,即 bootStrap.yml 会优先被加载。
原理:
- bootstrap.yml 用于应用程序上下文的引导阶段
- bootstrap.yml 由父Spring ApplicationContext加载
- bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的
- application.yml 可以用来定义应用级别的,如果搭配 spring-cloud-config 配置中心使用 application.yml,里面定义的配置可以实现动态替换
application.yml 配置
server:
port: 8060
bootstrap.yml 配置
spring:
application:
name: wei-config-client
cloud:
config:
uri: http://localhost:8050 # 配置服务中心的具体地址,即 config-server
name: config-client # 对应配置文件名 config-client-dev.properties 的 {application} 部分
profile: dev # 对应配置文件名 config-client-dev.properties 的 {profile} 部分
label: master # 使用 {label} 对应 Git 的分支名,如果配置中心使用的是本地存储,则该参数无用
3.2.3.读取配置
package com.wei.controller.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@Value("${config.env:env parameter error!}")
private String configEnv;
@Value("${config.tips:错误配置属性config.tips测试,此处应该为config.tip}")
private String configTip;
@GetMapping("/demo/info")
public String hello() {
String result = "[Config Client] env:" + configEnv + ", tip:" + configTip;
return result;
}
}
3.2.4.启动类
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WeiConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(WeiConfigClientApplication.class, args);
}
}
好了,到此,Spring Cloud Config Client 客户端的相关配置也已经完成。
3.2.5.测试
启动模块 wei-config-client 的启动类 WeiConfigClientApplication。
■访问开发环境:http://localhost:8060/demo/info,浏览器打印信息:
[Config Client] env:dev, tip:错误配置属性config.tips测试,此处应该为config.tip
如此,Config Client 从 Config Server 配置服务中心(Git仓库)成功获取到了开发环境配置项(env:dev)。
到此,Config Client 已经可以正常运作。
仔细的你,也许也已经发现,当使用 Spring 的@Value注解时,这里设置了默认值。比如,config.tips 属性在配置文件中是没有的,当编译时,会提示找不到该属性,如果使用@Value时设置了默认值,编译就不会报错,且请求返回的是其自定义的默认值。
但是,这里有个问题,上面的 Server 服务端可以获取到配置变更后的最新内容,可是 Client 端不会,修改配置文件 config-client-dev.properties 中的属性后,获取到的还是变更前的内容。
因为 Spring Cloud Config 分服务端和客户端,服务端负责将 Git 中存储的配置文件发布成 REST 接口,客户端可以从服务端 REST 接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置。
要实现动客户端的动态更新,请关注后面的章节。
4.总结
仓库中的配置文件名会被转换成 HTTP 接口,访问可以参照以下规则:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
上面的 URL 会映射 {application}-{profile}.properties 对应的配置文件,其中 {label} 对应 Git 上不同的分支,默认为 master。以本节使用的 config-client-dev.properties 配置文件为例,它的 application 是 config-client,profile 是 dev。
此时架构:
![](https://i-blog.csdnimg.cn/blog_migrate/af802124fed202a79b10986f4e4dcd17.png)
参考资料:https://springcloud.cc/spring-cloud-config.html
本节源码:https://github.com/itanping/wei-springcloud/tree/master/chapter05-config
下一节,请继续关注:SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
6.物语
SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】
SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
SpringCloud进击 | 四浅出:断路器与容错(Hystrix)【Finchley版本】
SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
SpringCloud进击 | 七浅出:配置中心(Git配置与更新)【Finchley版本】
SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
SpringCloud进击 | 二深入:配置中心(消息总线)【Finchley版本】
SpringCloud进击 | 三深入:服务链路跟踪(Spring Cloud Sleuth)【Finchley版本】
SpringCloud进击 | 四深入:服务链路跟踪(Sleuth+Zipkin+RabbitMQ整合)【Finchley版本】
SpringCloud进击 | 五深入:断路器监控(Hystrix Dashboard)【Finchley版本】
SpringCloud进击 | 六深入:断路器聚合监控(Hystrix Turbine)【Finchley版本】
SpringCloud进击 | 七深入:高可用的服务注册中心【Finchley版本】