Spring Cloud Config 是一个全新的项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,他分为服务端和客户端两个部分。服务端也称为分布式配置中心,是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密、解密信息等访问接口;而客户端则是为微服务架构中的各个微服务应用,通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。服务端与客户端的结构图如下:
Spring Cloud 程序在进行初始化时会先建立一个 Bootstrap Context(引导上下文),然后再创建主应用的上下文,主应用程序上下文读取的时 application.yml (或 properties)文件,而引导上下文则会读取 bootstrap.yml(或 properties)文件。因为,applicatyon.yml 的配置会在 bootstrap.yml 后加载,如果存在两份配置文件同时存在,且存在相同 key 的配置,则 application.yml 的配置会覆盖 bootstrap.yml 的配置。下面是 Spring Boot 对配置文件读取的优先级:
- 命令行中传入的参数
- SPRING_APPLICATION_JSON中的属性,SPRING_APPLICATION_JSON 是以JSON格式配置在系统环境变量中的内容
- java:comp/env 中的 JNDI 属性
- java 的系统属性,可以通过System.getProperties()获取的内容
- 操作系统的环境变量
- 通过 random.* 配置的随机属性
- 位于当前应用 Jar 包之外,针对不同{profile}环境的配置文件内容
- 位于当前应用 Jar 包之内,针对不同{profile}环境的配置文件内容
- 位于当前应用 Jar 包之外的 application.properties 配置内容
- 位于当前应用 Jar 包之内的 application.properties 配置内容
- 在 @Configuration 注解修改的类,通过 @PropertySource 注解定义的属性
- 应用默认属性,使用 SpringApplication.setDefaultProperties 定义的内容
可以看到其中 7 和 9 步骤都是从应用Jar包之外读取配置文件,所以,实现外部化配置的原理就是从此切入,为其指定外部配置文件的加载位置来取代 Jar 包之内的配置内容。
集群配置中心示例
- 分布式配置中心
- 创建项目
创建 Spring Cloud 项目,增加 spring-cloud-config-server 依赖,由于使用 SVN 仓库,还需要增加svnkit 依赖,POM.xml 文件内容如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.lixue.config</groupId>
<artifactId>spring-cloud-config</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-config</name>
<description></description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath/><!--lookupparentfromrepository-->
</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.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</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>
- 增加配置
在 src/main/resources 目录中创建 application.yml 配置文件,增加基本配置和SVN仓库相关配置,如下:
#配置应用名称
spring:
application:
name:spring-cloud-config
#配置使用subversion仓库读取配置,相关配置还有git、native(本地文件)、vault
profiles:
active:subversion
cloud:
config:
server:
#配置svn仓库地址和账户
svn:
uri:http://192.168.2.210/svn/config
username:lixue
password:liyong
#配置默认分支,默认值为trunk
default-label:trunk
#设置本地文件存储目录
basedir:e: empconfig
#服务端口
server:
port:8080
配置是通过 spring.profiles.active 的值来决定使用那种仓库读取配置文件,主要有以下四种:
- git:默认值,表示从 Git 仓库读取配置文件
- subversion:表示从 SVN 仓库读取配置文件
- native:表示从本地文件系统读取配置文件,本地文件默认是在 /src/main/resources目录下读取文件,也可以使用 spring.cloud.config.server.native.searchLocations 属性来指定具体的配置文件位置
- vault:表示从 vault 读取配置文件,Vault 是一款资源控制工具,可对资源实现安全访问
- 启动类
在启动类使用注解 @EnableConfigServer 来标注,启动配置服务器的功能,如下:
package org.lixue.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class SpringCloudConfigApplication{
public static void main(String[]args){
SpringApplication.run(SpringCloudConfigApplication.class,args);
}
}
- SVN仓库
我们创建一个 SVN 仓库,必须要支持使用 http 或 https 来访问仓库内容,配置方式参考"用 Apache 和 Subversion 搭建安全的版本控制环境",其目录结构如下:
- 配置客户端
- 创建项目
创建 Spring Cloud 项目,增加 spring-cloud-config 依赖,POM.xml 文件内容如下:
<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.lixue.config</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-cloud-config-client</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath/><!--lookupparentfromrepository-->
</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.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</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>
- 启动类
配置客户端的启动类,不需要额外处理,这里我们增加了一个 REST 服务,用来验证配置获取,如下:
package org.lixue.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class SpringCloudConfigClientApplication{
public static void main(String[]args){
SpringApplication.run(SpringCloudConfigClientApplication.class,args);
}
@Autowired
private Environment environment;
@RequestMapping(path="/",method=RequestMethod.GET)
public String getApplicationName(){
return environment.getProperty("spring.application.name");
}
}
- 增加配置
客户端要在引导程序中读取配置服务器的配置,因此要 src/main/resources 目录下创建 bootstrap.yml 配置,并增加配置中心的相关配置项:
#配置应用名称
spring:
application:
name:spring-cloud-config-client
#配置分布式配置中心地址和相关配置
cloud:
config:
uri:http://localhost:8080
#表示分支,客户端配置后,会替换到分布式配置中心的default-lable配置
label:test
#表示配置文件名称,如果不配置则使用spring.application.name配置项
name:spring-cloud-config-client
#表示配置文件的profile,实际获取文件为${spring.cloud.config.name}-${spring.cloud.config.profile}.yml
profile:dev
以上配置表示要获取的地址为 http://localhost:8080/test/spring-cloud-config-client-dev.yml ,地址的解析如下:
${config.uri}/${config.label}/$(config.name}-${config.profile}.(yml 或 properties)
其中,spring.cloud.config.name 如果不存在,则会使用 spring.application.name ,如果都不存在,则会使用 "application";在实际环境中,可能存在多个配置文件,例如专门针对 zuul 的,专门针对 hystrix 的,可以在spring.cloud.config.profile 配置项配置多个,以逗号分隔,这样就会去读取多个配置文件。
- 测试验证
测试验证需要依赖 SVN 和分布式配置中心,首先启动 SVN 和 spring-cloud-config 项目,然后启动 spring-cloud-config-client 项目,在 SVN 的 test 分支下创建文件 spring-cloud-config-client-dev.yml 并提交,文件内容如下:
spring:
application:
name:spring-cloud-config-client-test-branch-dev
server:
port:8012
访问地址 http://localhost:8012/ 可以看到如下返回,表示从 SVN 获取到的配置文件已经生效:
spring-cloud-config-client-test-branch-dev