为什么要统一管理配置?
- 集中管理配置文件
- 不同环境不同配置
- 运行期间动态调整配置
- 自动刷新
分布式配置中心
spring cloud config
是spring cloud
团队创建的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端和客户端两部分,其中服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息,加密/解密信息等访问接口,而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。spring cloud config
实现了对服务端和客户端中环境变量和属性设置的抽象映射,所以它除了适用于spring构建的应用程序之外,也可以在任何其他语言运行的应用程序中使用。由于spring cloud config
实现的配置中心默认采用git来存储配置信息,所以使用spring cloud config
构建的配置服务器,天然就支持对微服务应用配置信息的版本管理,并且可以通过git
客户端工具来方便地管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如说svn仓库,本地化文件系统。
快速入门
构建一个基于git存储的分布式配置中心,并在客户端中演示如何通过配置指定微服务应用的所属配置中心,并让其能够从配置中心获取配置信息并绑定到代码的整个过程。
构建配置中心
创建一个名为config-server-git
的服务
第一步,加入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
我构建的是父子依赖,关于spring cloud
的版本定义可以在父依赖中查看,相关代码可以在博客最下方查看。
第二步,创建springboot
程序主类,加上注解@EnableConfigServer
,开启spring cloud config
的服务端功能。
@EnableConfigServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
第三步,在application.yml
中添加配置服务的基本信息以及git仓库的相关信息
spring:
application:
name: config-server-git
cloud:
config:
server:
git:
uri: http://git.oschina.net/zhihaomiao/config-repo-demo
username: zhihao.miao
password: 13579qwertyu
search-paths: config-repo
server:
port: 9090
其中git的配置分别表示如下内容
-
spring.cloud.config.server.git.uri
: 配置的git仓库位置 -
spring.cloud.config.server.git.search-paths
: 配置仓库路径下的相对搜索位置,可以配置多个 -
spring.cloud.config.server.git.username
: 访问git的用户名 -
spring.cloud.config.server.git.password
: 访问git仓库的用户密码
配置规则详解
在git配置信息中指定的仓库位置,http://git.oschina.net/zhihaomiao/config-repo-demo/config-repo
目录下创建五个不同的配置文件
zhihao.yml
zhihao-dev.yml
zhihao-test.yml
zhihao-pro.yml
application.yml
内容分别是:
zhihao.yml
from: git-default-1.0
spring:
datasource:
username: user_default
zhihao-dev.yml
from: git-dev-1.0
spring:
datasource:
username: user_dev
zhihao-test.yml
from: git-test-1.0
spring:
datasource:
username: user_test
zhihao-pro.yml
from: git-pro-1.0
spring:
datasource:
username: user_pro
application.yml
from: git-pro-1.0
spring:
datasource.
username:
zhihao.miao1
为了测试版本控制,在git
仓库的master
分支中,我们为from
属性加入1.0
的后缀,同时创建一个config-label-test
分支,并将各配置文件中的值用2.0
做为后缀.
完成上面的工作我们就可以通过url来访问这些配置内容了。
* /{application}/{profile}/[{label}]
* /{application}-{profile}.yml
* /{label}/{application}-{profile}.yml
* /{application}-{profile}.properties
* /{label}/{application}-{profile}.properties
上面的url会映射{application}-{profile}.yml
对应的配置文件,其中{label}
对应git上不同的分支,默认是master
。我们可以尝试构造不同的url来访问不同的配置内容,比如,要访问config-label-test
分支,zhihao
应用的prod环境,就可以访问这个url:http://localhost:9090/zhihao/pro/config-label-test
{
name: "zhihao",
profiles: [
"pro"
],
label: "config-label-test",
version: "13c5f9da27b75ea85b1585803a39b00d8a9b75d4",
state: null,
propertySources: [
{
name: "http://git.oschina.net/zhihaomiao/config-repo-demo/config-repo/zhihao-pro.yml",
source: {
from: "git-pro-3.0",
spring.datasource.username: "user_pro3.0"
}
},
{
name: "http://git.oschina.net/zhihaomiao/config-repo-demo/config-repo/zhihao.yml",
source: {
from: "git-test-2.0",
spring.datasource.username: "user_default"
}
},
{
name: "http://git.oschina.net/zhihaomiao/config-repo-demo/config-repo/application.yml",
source: {
from: "git-pro-2.0",
spring.datasource.username: "zhihao.miao2"
}
}
]
}
我们看到json中返回了应用名是zhihao
,环境是prod
,分支名是config-label-test
,以及default
环境和prod
环境的配置内容,还包括applocation.yml的内容。另外之前提到的version
,也可以观察到,对应于最后提交的git的commit_id
。
也可以输入http://localhost:9090/abc/pro/config-label-test
,此时没有abc.yml
文件,就会去application.yml
文件中查找,所以application.yml
可以匹配任何{application}
{
name: "abc",
profiles: [
"pro"
],
label: "config-label-test",
version: "13c5f9da27b75ea85b1585803a39b00d8a9b75d4",
state: null,
propertySources: [
{
name: "http://git.oschina.net/zhihaomiao/config-repo-demo/config-repo/application.yml",
source: {
from: "git-pro-2.0",
spring.datasource.username: "zhihao.miao2"
}
}
]
}
同时,我们可以看到config-server-git
的控制台中还输出了下面的内容,配置服务器在从git中获取了配置信息后,会存储一份在config-server-git
的文件系统中,实质上config-server-git
是通过git clone
命令将配置内容复制了一份在本地存储,然后读取这些内容并返回给微服务应用进行加载。
2017-08-15 22:10:07.568 INFO 28701 --- [io-9090-exec-10] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5ac2c286: startup date [Tue Aug 15 22:10:07 CST 2017]; root of context hierarchy
2017-08-15 22:10:07.579 INFO 28701 --- [io-9090-exec-10] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/p0/kw_s_8xj2gqc929nys7cj2yh0000gn/T/config-repo-2847833657021753497/config-repo/application-pro.yml
2017-08-15 22:10:07.579 INFO 28701 --- [io-9090-exec-10] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/p0/kw_s_8xj2gqc929nys7cj2yh0000gn/T/config-repo-2847833657021753497/config-repo/application.yml
2017-08-15 22:10:07.579 INFO 28701 --- [io-9090-exec-10] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@5ac2c286: startup date [Tue Aug 15 22:10:07 CST 2017]; root of context hierarchy
config-server-git
通过从git在本地的仓库暂存,可以有效的防止当git仓库出现故障而引起无法加载配置信息的情况。我们可以通过断开网络(断开wifi),再次发起从http://localhost:9090/zhihaomiao/pro/config-label-test
请求,在控制台中可以输出如下内容,这些内容源于之前访问时存在于config-server-git服务本地文件系统中的配置信息。
2017-08-15 22:23:15.002 WARN 28701 --- [nio-9090-exec-5] .c.s.e.MultipleJGitEnvironmentRepository : Could not fetch remote for config-label-test remote: http://git.oschina.net/zhihaomiao/config-repo-demo
2017-08-15 22:23:15.074 INFO 28701 --- [nio-9090-exec-5] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7060493e: startup date [Tue Aug 15 22:23:15 CST 2017]; root of context hierarchy
2017-08-15 22:23:15.088 INFO 28701 --- [nio-9090-exec-5] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/p0/kw_s_8xj2gqc929nys7cj2yh0000gn/T/config-repo-2847833657021753497/config-repo/application-pro.yml
2017-08-15 22:23:15.089 INFO 28701 --- [nio-9090-exec-5] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/var/folders/p0/kw_s_8xj2gqc929nys7cj2yh0000gn/T/config-repo-2847833657021753497/config-repo/application.yml
2017-08-15 22:23:15.089 INFO 28701 --- [nio-9090-exec-5] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7060493e: startup date [Tue Aug 15 22:23:15 CST 2017]; root of context hierarchy
通过http访问git server资源的格式:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
比如
http://localhost:9090/config-label-test/abc-pro.yml
等等。
客户端配置映射
如何在微服务应用中获取上面的配置信息?
- 创建一个应用
config-client
,并在pom文件中引入依赖:
<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-actuator</artifactId>
</dependency>
</dependencies>
- 创建springboot的应用主类:
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class,args);
}
}
- 创建
bootstrap.yml
配置,来获取配置文件的config-server-git
位置,如下:
spring:
application:
name: zhihaomiao
cloud:
config:
uri: http://localhost:9090/
profile: pro
label: config-label-test
server:
port: 8080
上述配置参数与git中存储的配置文件中各个部分的对应关系如下:
-
spring.application.name
: 对应配置文件规则中的{application}
部分 -
spring.cloud.config.profile
:对应配置文件规则中{profile}
部分 -
spring.cloud.config.label
:对应配置文件规则中的{label}
部分 -
spring.cloud.config.uri
:配置中心config-server
的地址。
这里需要格外注意,上面的属性必须配置在bootstrap.yml
中,这样config-server
中的配置信息才能被正确加载。springboot对配置文件的加载顺序,对于本应用jar包之外的配置文件加载会优于应用jar包内的配置内容,而通过bootstrap.yml
对config-server-git
的配置,使得该应用会从config-server-git
中获取一些外部配置信息,这些信息的优先级比本地的内容要高,从而实现了外部化配置。
springboot应用配置文件加载的顺序是bootstrap.yml-> config server中的配置 -> application.yml中的配置,这样的顺序进行加载。
如果在application.yml中配置和远程配置相同的配置
application.yml
from: git-pro-1.0
spring:
datasource:
username: user_pro
那么application.yml中不会覆盖当前在config server中的配置,并且读取的还是远程仓库的配置,那么如何进行属性覆盖呢,可以看下面的博客。
@RestController
public class ConfigClientController {
private Logger log = LoggerFactory.getLogger(getClass());
@Value("${spring.datasource.username}")
private String username;
@Value("${from}")
private String from;
@GetMapping("/index")
public String index(){
log.info("username="+username+",form=="+from);
return "username="+username+",form=="+from;
}
}
访问
http://localhost:8080/index
页面显示:
username=user_pro,form==git-pro-2.0
服务端详解
- 远程git仓库:用来存储配置文件的地方,快速入门中应用名为
zhihao
的多环境配置文件:zhihao-{profile}.properties
. - config server:这是我们快速入门中构建的分布式配置中心,
config-server-git
项目,在该工程中指定了所要连接的git仓库位置以及账户,密码等连接信息。 - 本地git仓库:在
config server
的文件系统中,每次客户端请求获取配置信息时,Config Server
从git仓库中获取最新的配置到本地,然后在本地git仓库中读取并返回。当远程仓库无法获取时,直接将本地的内容返回。 - Service A,Service B:具体的微服务应用,他们指定了
config Server
地址,从而实现从外部化获取应用自己要用的配置信息。这些应用在启动的时候,会向config server
请求获取配置信息来进行加载。
客户端应用从配置管理中获取配置信息遵从下面的执行流程:
- 应用启动时,根据
bootstrap.yml
中配置的应用名{application}
,环境名{profile}
,分支名{label}
,向config server
请求获取配置信息 -
config server
根据自己维护的git仓库信息和客户端传递过来的配置信息去查找配置信息。 - 根据
git clone
命令将找到的配置信息下载到Config Server
的文件系统中 -
Config Server
创建Spring的ApplictionContext实例,并从git本地仓库中加载配置文件,最后将这些配置内容读取出来返回给客户端应用。 - 客户端应用在获取外部配置文件后加载到客户端的
ApplicationContext
实例,该配置内容的优先级高于客户端jar包内部的配置内容,所以在jar包中重复的内容不再被加载。
Config Server
巧妙的通过git clone
将配置信息存于本地,起到了缓存的作用,即使当git服务端无法访问的时候,依然可以取Config Server
中缓存内容进行试验。
参考文档:
官网The Bootstrap Application Context
官网Quick Start
官网Client Side Usage