Spring Cloud Config 是 Spring Cloud 家族中最早的配置中心,虽然后来又发布了 Consul 可以代替配置中心功能,但是 Config 依然适用于 Spring Cloud 项目,通过简单的配置即可实现功能。
配置文件是我们再熟悉不过的了,尤其是 Spring Boot 项目,除了引入相应的 maven 包之外,剩下的工作就是完善配置文件了,例如 mysql、redis 、security 相关的配置。除了项目运行的基础配置之外,还有一些配置是与我们业务有关系的,比如说七牛存储、短信相关、邮件相关,或者一些业务上的开关。
对于一些简单的项目来说,我们一般都是直接把相关配置放在单独的配置文件中,以 properties 或者 yml 的格式出现,更省事儿的方式是直接放到 application.properties 或 application.yml 中。但是这样的方式有个明显的问题,那就是,当修改了配置之后,必须重启服务,否则配置无法生效。
目前有一些用的比较多的开源的配置中心,比如携程的 Apollo、蚂蚁金服的 disconf 等,对比 Spring Cloud Config,这些配置中心功能更加强大。有兴趣的可以拿来试一试。
接下来,我们开始在 Spring Boot 项目中集成 Spring Cloud Config,并以 github 作为配置存储。除了 git 外,还可以用数据库、svn、本地文件等作为存储。主要从以下三块来说一下 Config 的使用。
1.基础版的配置中心(不集成 Eureka);
2.结合 Eureka 版的配置中心;
3.实现配置的自动刷新;
以上三步整合实现Eureka+自动配置刷新,Eureka是为了实现客户端通过注册中心获取配置中心的URL,进而读取远程仓库配置的配置文件。
实现最简单的配置中心
最简单的配置中心,就是启动一个服务作为服务方,之后各个需要获取配置的服务作为客户端来这个服务方获取配置。
先在 github 中建立配置文件
我创建的仓库地址为:配置中心仓库
目录结构如下:
配置文件的内容大致如下,用于区分,略有不同。
data:
env: config-eureka-dev
user:
username: eureka-client-user
password: 1291029102
注意文件的名称不是乱起的,例如上面的 config-single-client-dev.yml 和 config-single-client-prod.yml 这两个是同一个项目的不同版本,项目名称为 config-single-client, 一个对应开发版,一个对应正式版。config-eureka-client-dev.yml 和 config-eureka-client-prod.yml 则是另外一个项目的,项目的名称就是 config-eureka-client 。
创建配置中心服务端
1、新建 Spring Boot 项目,引入 config-server 和 starter-web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring cloud config 服务端包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2、配置 config 相关的配置项
bootstrap.yml 文件
spring:
application:
name: config-single-server # 应用名称
cloud:
config:
server:
git:
uri: https://github.com/huzhicheng/config-only-a-demo #配置文件所在仓库
username: github 登录账号
password: github 登录密码
default-label: master #配置文件分支
search-paths: config #配置文件所在根目录
application.yml
server:
port: 3301
3、在 Application 启动类上增加相关注解 @EnableConfigServer
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动服务,接下来测试一下。
Spring Cloud Config 有它的一套访问规则,我们通过这套规则在浏览器上直接访问就可以。
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
{application} 就是应用名称,对应到配置文件上来,就是配置文件的名称部分,例如我上面创建的配置文件。
{profile} 就是配置文件的版本,我们的项目有开发版本、测试环境版本、生产环境版本,对应到配置文件上来就是以 application-{profile}.yml 加以区分,例如application-dev.yml、application-sit.yml、application-prod.yml。
{label} 表示 git 分支,默认是 master 分支,如果项目是以分支做区分也是可以的,那就可以通过不同的 label 来控制访问不同的配置文件了。
上面的 5 条规则中,我们只看前三条,因为我这里的配置文件都是 yml 格式的。根据这三条规则,我们可以通过以下地址查看配置文件内容:
http://localhost:3301/config-single-client/dev/master
http://localhost:3301/config-single-client/prod
http://localhost:3301/config-single-client-dev.yml
http://localhost:3301/config-single-client-prod.yml
http://localhost:3301/master/config-single-client-prod.yml
通过访问以上地址,如果可以正常返回数据,则说明配置中心服务端一切正常。
创建配置中心客户端,使用配置
配置中心服务端好了,配置数据准备好了,接下来,就要在我们的项目中使用它了。
1、引用相关的 maven 包。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring cloud config 客户端包 -->
<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>
2、初始化配置文件
bootstrap.yml
spring:
profiles:
active: dev
---
spring:
profiles: prod
application:
name: config-single-client
cloud:
config:
uri: http://localhost:3301
label: master
profile: prod
---
spring:
profiles: dev
application:
name: config-single-client
cloud:
config:
uri: http://localhost:3301
label: master
profile: dev
配置了两个版本的配置,并通过 spring.profiles.active 设置当前使用的版本,例如本例中使用的 dev 版本。
application.yml
server:
port: 3302
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
data:
env: NaN
user:
username: NaN
password: NaN
其中 management 是关于 actuator 相关的,接下来自动刷新配置的时候需要使用。
data 部分是当无法读取配置中心的配置时,使用此配置,以免项目无法启动。
3、要读取配置中心的内容,需要增加相关的配置类,Spring Cloud Config 读取配置中心内容的方式和读取本地配置文件中的配置是一模一样的。可以通过 @Value 或 @ConfigurationProperties 来获取。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、要读取配置中心的内容,需要增加相关的配置类,Spring Cloud Config 读取配置中心内容的方式和读取本地配置文件中的配置是一模一样的。可以通过 @Value 或 @ConfigurationProperties 来获取。
使用 @Value 的方式:
@Data
@Component
public class GitConfig {
@Value("${data.env}")
private String env;
@Value("${data.user.username}")
private String username;
@Value("${data.user.password}")
private String password;
}
使用 @ConfigurationProperties 的方式:
@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {
public static class UserInfo {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "UserInfo{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
private String env;
private UserInfo user;
}
4、增加一个 RESTController 来测试使用配置
@RestController
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping(value = "show")
public Object show(){
return gitConfig;
}
@GetMapping(value = "autoShow")
public Object autoShow(){
return gitAutoRefreshConfig;
}
}
5、项目启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动项目,访问 RESTful 接口
http://localhost:3302/show,结果如下:
{
"env": "localhost-dev-edit",
"username": "fengzheng-dev",
"password": "password-dev"
}
http://localhost:3302/autoShow,结果如下:
{
"env": "localhost-dev-edit",
"user": {
"username": "fengzheng-dev",
"password": "password-dev"
}
}
实现自动刷新
Spring Cloud Config 在项目启动时加载配置内容这一机制,导致了它存在一个缺陷,修改配置文件内容后,不会自动刷新。例如我们上面的项目,当服务已经启动的时候,去修改 github 上的配置文件内容,这时候,再次刷新页面,对不起,还是旧的配置内容,新内容不会主动刷新过来。
但是,总不能每次修改了配置后重启服务吧。如果是那样的话,还是不要用它了为好,直接用本地配置文件岂不是更快。
它提供了一个刷新机制,但是需要我们主动触发。那就是 @RefreshScope 注解并结合 actuator ,注意要引入 spring-boot-starter-actuator 包。
1、在 config client 端配置中增加 actuator 配置,上面大家可能就注意到了。
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
其实这里主要用到的是 refresh 这个接口
2、在需要读取配置的类上增加 @RefreshScope 注解,我们是 controller 中使用配置,所以加在 controller 中。
@RestController
@RefreshScope
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping(value = "show")
public Object show(){
return gitConfig;
}
@GetMapping(value = "autoShow")
public Object autoShow(){
return gitAutoRefreshConfig;
}
}
注意,以上都是在 client 端做的修改。
之后,重启 client 端,重启后,我们修改 github 上的配置文件内容,并提交更改,再次刷新页面,没有反应。没有问题。
接下来,我们发送 POST 请求到 http://localhost:3302/actuator/refresh 这个接口,用 postman 之类的工具即可,此接口就是用来触发加载新配置的,返回内容如下:
[
"config.client.version",
"data.env"
]
之后,再次访问 RESTful 接口,http://localhost:3302/autoShow 这个接口获取的数据已经是最新的了,说明 refresh 机制起作用了。
而 http://localhost:3302/show 获取的还是旧数据,这与 @Value 注解的实现有关,所以,我们在项目中就不要使用这种方式加载配置了。
在 github 中配置 Webhook
这就结束了吗,并没有,总不能每次改了配置后,就用 postman 访问一下 refresh 接口吧,还是不够方便呀。 github 提供了一种 webhook 的方式,当有代码变更的时候,会调用我们设置的地址,来实现我们想达到的目的。
1、进入 github 仓库配置页面,选择 Webhooks ,并点击 add webhook;
2、之后填上回调的地址,也就是上面提到的 actuator/refresh 这个地址,但是必须保证这个地址是可以被 github 访问到的。如果是内网就没办法了。这也仅仅是个演示,一般公司内的项目都会有自己的代码管理工具,例如自建的 gitlab,gitlab 也有 webhook 的功能,这样就可以调用到内网的地址了。
使用 Spring Cloud Bus 来自动刷新多个端
Spring Cloud Bus 将分布式系统的节点与轻量级消息代理链接。这可以用于广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,Bus 就像一个扩展的 Spring Boot 应用程序的分布式执行器,但也可以用作应用程序之间的通信渠道。
—— Spring Cloud Bus 官方解释
如果只有一个 client 端的话,那我们用 webhook ,设置手动刷新都不算太费事,但是如果端比较多的话呢,一个一个去手动刷新未免有点复杂。这样的话,我们可以借助 Spring Cloud Bus 的广播功能,让 client 端都订阅配置更新事件,当配置更新时,触发其中一个端的更新事件,Spring Cloud Bus 就把此事件广播到其他订阅端,以此来达到批量更新。
1、Spring Cloud Bus 核心原理其实就是利用消息队列做广播,所以要先有个消息队列,目前官方支持 RabbitMQ 和 kafka。
这里用的是 RabbitMQ, 所以先要搭一套 RabbitMQ 环境。请自行准备环境,这里不再赘述。我是用 docker 直接创建的,然后安装了 rabbitmq-management 插件,这样就可以在浏览器访问 15672 查看 UI 管理界面了。
2、在 client 端增加相关的包,注意,只在 client 端引入就可以。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
3、在配置文件中增加 RabbitMQ 相关配置,默认的端口应该是 5672 ,因为我是用 docker 创建的,所以有所不同。
spring:
rabbitmq:
host: localhost
port: 32775
username: guest
password: guest
4、启动两个或多个 client 端,准备来做个测试
在启动的时候分别加上 vm option:-Dserver.port=3302 和 -Dserver.port=3303 ,然后分别启动就可以了。
5、分别打开 http://localhost:3302/autoShow 和 http://localhost:3303/autoShow,查看内容,然后修改 github 上配置文件的内容并提交。再次访问这两个地址,数据没有变化。
6、访问其中一个的 actuator/bus-refresh 地址,注意还是要用 POST 方式访问。之后查看控制台输出,会看到这两个端都有一条这样的日志输出
o.s.cloud.bus.event.RefreshListener: Received remote refresh request. Keys refreshed
7、再次访问第 5 步的两个地址,会看到内容都已经更新为修改后的数据了。
综上所述,当我们修改配置后,使用 webhook ,或者手动触发的方式 POST 请求一个 client 端的 actuator/bus-refresh 接口,就可以更新给所有端了。
结合 Eureka 使用 Spring Cloud Config
以上讲了 Spring Cloud Config 最基础的用法,但是如果我们的系统中使用了 Eureka 作为服务注册发现中心,那么 Spring Cloud Config 也应该注册到 Eureka 之上,方便其他服务消费者使用,并且可以注册多个配置中心服务端,以实现高可用。
好的,接下来就来集成 Spring Cloud Config 到 Eureka 上。
在 github 仓库中增加配置文件
启动 Eureka Server
首先启动一个 Eureka Server,之前的文章有讲过 Eureka ,可以回过头去看看。Spring Cloud Eureka 实现服务注册发现,为了清楚,这里还是把配置列出来
1、pom 中引入相关包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、设置配置文件内容
bootstrap.yml
spring:
application:
name: kite-eureka-center
security:
user:
name: test # 用户名
password: 123456 # 密码
cloud:
inetutils: ## 网卡设置
ignoredInterfaces: ## 忽略的网卡
- docker0
- veth.*
- VM.*
preferredNetworks: ## 优先的网段
- 192.168
application.yml
server:
port: 3000
eureka:
instance:
hostname: eureka-center
appname: 注册中心
client:
registerWithEureka: false # 单点的时候设置为 false 禁止注册自身
fetchRegistry: false
serviceUrl:
defaultZone: http://test:123456@localhost:3000/eureka
server:
enableSelfPreservation: false
evictionIntervalTimerInMs: 4000
3、Application 启动类
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、启动服务,在浏览器访问 3000 端口,并输出用户名 test,密码 123456 即可进入 Eureka UI
配置 Spring Cloud Config 服务端
服务端和前面的相比也就是多了注册到 Eureka 的配置,其他地方都是一样的。
1、在 pom 中引入相关的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 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>
2、配置文件做配置
application.yml
server:
port: 3012
eureka:
client:
serviceUrl:
register-with-eureka: true
fetch-registry: true
defaultZone: http://test:123456@localhost:3000/eureka/
instance:
preferIpAddress: true
spring:
application:
name: config-eureka-server
cloud:
config:
server:
git:
uri: https://github.com/huzhicheng/config-only-a-demo
username: github 用户名
password: github 密码
default-label: master
search-paths: config
相比于不加 Eureka 的版本,这里仅仅是增加了 Eureka 的配置,将配置中心注册到 Eureka ,作为服务提供者对外提供服务。
3、启动类,在 @EnableConfigServer 的基础上增加了 @EnableEurekaClient,另外也可以用 @EnableDiscoveryClient 代替 @EnableEurekaClient
@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、启动服务,之后访问 Eureka ,可以看到服务已注册成功
配置 Spring Cloud Config 客户端
客户端的配置相对来说变动大一点,加入了 Eureka 之后,就不用再直接和配置中心服务端打交道了,要通过 Eureka 来访问。另外,还是要注意客户端的 application 名称要和 github 中配置文件的名称一致。
1、pom 中引入相关的包
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、配置文件
bootstrap.yml
eureka:
client:
serviceUrl:
register-with-eureka: true
fetch-registry: true
defaultZone: http://test:123456@localhost:3000/eureka/
instance:
preferIpAddress: true
spring:
profiles:
active: dev
---
spring:
profiles: prod
application:
name: config-eureka-client
cloud:
config:
label: master
profile: prod
discovery:
enabled: true
service-id: config-eureka-server
---
spring:
profiles: dev
application:
name: config-eureka-client
cloud:
config:
label: master #指定仓库分支
profile: dev #指定版本 本例中建立了dev 和 prod两个版本
discovery:
enabled: true # 开启
service-id: config-eureka-server # 指定配置中心服务端的server-id
除了注册到 Eureka 的配置外,就是配置和配置中心服务端建立关系。
其中 service-id 也就是服务端的application name。
application.yml
server:
port: 3011
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
data:
env: NaN
user:
username: NaN
password: NaN
3、启动类,增加了 @EnableEurekaClient 注解,可以用 @EnableDiscoveryClient 代替
@SpringBootApplication
@EnableEurekaClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、另外的配置实体类和 RESTController 和上面的一样,没有任何更改,直接参考即可。
5、启动 client 端,访问 http://localhost:3011/autoShow,即可看到配置文件内容。
这个例子只是介绍了和 Eureka 结合的最基础的情况,还可以注册到高可用的 Eureka 注册中心,另外,配置中心服务端还可以注册多个实例,同时保证注册中心的高可用。
注意事项
1. 在 git 上的配置文件的名字要和 config 的 client 端的 application name 对应;
2. 在结合 eureka 的场景中,关于 eureka 和 git config 相关的配置要放在 bootstrap.yml 中,否则会请求默认的 config server 配置,这是因为当你加了配置中心,服务就要先去配置中心获取配置,而这个时候,application.yml 配置文件还没有开始加载,而 bootstrap.yml 是最先加载的。
高可用实现配置
引入集群和restry机制
当要将配置中心部署到生产环境中时,与服务注册中心一样,我们也希望它是一个高可用的应用。SpringCloudCoiifig实现服务端的高可用非常简单,主要有以下两种方式。
- 传统模式:不需要为这些服务端做任何额外的配置,只需要遵守一个配置规则,将所有的Config Server都指向同一个Git仓库,这样所有的配置内容就通过统一的共享文件系统来维护。而客户端在指定Config Server位置时,只需要配置Config Server上层的负载均衡设备地址即可,就如下图所示的结构:
- 服务模式:除了上面这种传统的实现模式之外,我们也可以将Config Server作为一个普通的微服务应用,纳入Eureka的服务治理体系中。这样我们的微服务应用就可以通过配置中心的服务名来获取配置信息,这种方式比起传统的实现模式来说更加有利于维护,因为对于服务端的负载均衡配置和客户端的配置中心指定都通过服务治理机制一并解决了,既实现了高可用,也实现了自维护。由于这部分的实现需要客户端的配合,具体示例读者可详细阅读“客户端详解”一节中的“服务化配置中心”小节
客户端详解
在学习了关于Spring Cloud Config 服务端的大量配置和使用细节之后,接下来我们将通过下面的内容继续学习Spring Cloud Config客户端的使用与配置。
URI指定配置中心
Spring Cloud Config 的客户端在启动的时候,默认从工程的classpath中加载配置信息并启动应用,只有当我们配置spring.cloud .config.uri的时候,客户端应用才会尝试连接Spring Cloud Config的服务端来获取远程配置信息并初始化Spring环境配置。同时,我们必须将该参数配置在bootstrap.propertie、环境变量或是其他优先级高于应用Jar包内的配置信息中,才能正确加载到远程配置。若不指定spring.cloud.config.uri参数的话,Spring Cloud Config的客户端会默认尝试连接http://10.0.45.103:8080。
项目github地址:[email protected]:13849141963/spring-cloud.git
【Dalston版】
在之前的快速入门示例中,我们就是以这种方式实现的,就如下面的配置,其中spring.application.name和spring.cloud.config.profile用于定位配置信息。
-
spring.application.name=springcloud-config-client
-
# 指明远程仓库的分支
-
spring.cloud.config.label=master
-
# dev开发环境配置文件 test测试环境 pro正式环境
-
spring.cloud.config.profile=dev
-
# 配置中心config-server的地址
-
#spring.cloud.config.uri=http://10.0.45.103:8080/
服务化配置中心
在前几篇博客中,我们己经学会了如何构建服务注册中心、如何发现与注册服务。那么Config Server是否也能以服务的方式注册到服务中心,并被其他应用所发现来实现配置信息的获取呢?答案是肯定的。在Spring Cloud中,我们也可以把Config Server视为微服务架构中与其他业务服务一样的一个基本单元。
下面,我们就来详细介绍如何将Config Server注册到服务中心,并通过服务发现来访问Config Server并获取Git仓库中的配置信息。下面的内容将基于快速入门中实现的 springcloud-config-server和springcloud-config-client工程来进行改造实现。
服务端配置
1、在springcloud-config-server 的 pom.xml 中增加spring-cloud-starter-eureka,spring-cloud-config-server依赖,以实现将分布式配置中心加入Eureka的服务治理体系。
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.13.RELEASE</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
<!--分布式配置中心-->
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-config-server</artifactId>
-
</dependency>
-
<!--Eureka服务注册中心-->
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka-server</artifactId>
-
</dependency>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
2、在application.properties配置文件中配置参数eureka.client.service-url.defaultZone已指定服务注册中心的位置,详细内容如下:
-
spring.application.name=springcloud-config-server
-
server.port=8080
-
# 配置git仓库地址
-
spring.cloud.config.server.git.uri=https://github.com/13849141963/spring-config-file/
-
# 配置仓库的分支
-
spring.cloud.config.label=master
-
# 配置仓库路下的相对搜索位置.可以配置多个
-
spring.cloud.config.server.git.search-paths=respoitory
-
# 访问git仓库的用户名
-
spring.cloud.config.server.git.username=13849141963
-
# 访问git仓库的用户密码 如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写
-
spring.cloud.config.server.git.password=********
-
#将分布式配置中心交给eureka集群注册中心来管理
-
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer3:3333/eureka/,http://peer2:2222/eureka/
-
#虽然SpringCloudConfig提供这样的功能,但是为了支持更好的内容管理和版本控制等强大功能,还是推荐使用Git仓库的方式
-
#不使用git仓库或者svn仓库的存储方式 configSever会默认从应用的src/main/resources目录下搜寻文件
-
#spring.profiles.active=native
-
#如果需要指定搜索配置文件的路径,通过这个属性来指定具体的配置文件位置
-
#spring.cloud.config.server.native.search-locations=文件位置
3、在应用主类中,新增@EnableDiscoveryClient注解,用来将springcloud-config-server应用注册到上面的服务注册中心上去。
-
//分布式配置中心注解
-
@EnableConfigServer
-
//发现注册中心
-
@EnableEurekaClient
-
@SpringBootApplication
-
public class SpringcloudConfigServerApplication {
-
public static void main(String[] args) {
-
SpringApplication.run(SpringcloudConfigServerApplication.class, args);
-
}
-
}
4、启动该应用,并访问eureka集群http://10.0.45.103:1111,http://10.0.45.103:2222,http://10.0.45.103:3333,可以在Eureka Server的信息面板中看到springcloud-config-server已经被注册了。
客户端配置
1、在springcloud-config-client的pom.xml中新增spring-cloud-starter-eureka依赖,以实现客户端发现springcloud-config-server服务,具体配置如下:
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>1.5.13.RELEASE</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
<!--分布式配置中心-->
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-config</artifactId>
-
</dependency>
-
<!--Eureka服务注册中心-->
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-eureka-server</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-dependencies</artifactId>
-
<version>Dalston.RC1</version>
-
<type>pom</type>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
2、在bootstrap.properties文件中,按如下配置:
-
spring.application.name=springcloud-config-client
-
# 指明远程仓库的分支
-
spring.cloud.config.label=master
-
# dev开发环境配置文件 test测试环境 pro正式环境
-
spring.cloud.config.profile=dev
-
# 配置中心config-server的地址 在configServer分布式配置中心没有在eureka注册中心注册时,指定该ConfigServer的服务器地址通过访问Controller
-
# 来测试客户端获取git仓库的某个文件内容,之后ConfigServer在注册中心进行注册就可以使用service-id属性来指定分布式服务的名称,直接使用分布式服务
-
#spring.cloud.config.uri=http://10.0.45.103:8080/
-
#端口
-
server.port=7001
-
#开启通过服务来访问ConfigServer的功能
-
spring.cloud.config.discovery.enabled=true
-
#指定分布式配置中心服务名称
-
spring.cloud.config.discovery.service-id=springcloud-config-server
-
#将分布式配置中心交给eureka集群注册中心来管理
-
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer3:3333/eureka/,http://peer2:2222/eureka/
-
#关闭刷新安全认证
-
management.security.enabled=false
-
#和重试机制相关的配置有如下四个:
-
# 配置重试次数,默认为6
-
spring.cloud.config.retry.max-attempts=6
-
# 间隔乘数,默认1.1
-
spring.cloud.config.retry.multiplier=1.1
-
# 初始重试间隔时间,默认1000ms
-
spring.cloud.config.retry.initial-interval=1000
-
# 最大间隔时间,默认2000ms
-
spring.cloud.config.retry.max-interval=2000
其中,通过eureka.client.service-url.defaultZone参数指定服务注册中心,用于服务注册与发现;在将spring.cloud.config.discovery.enabled参数设置为true,开启通过服务来访问Config Server的功能;最后利用spring.cloud.config.discovery.serviceId参数来指定Config Server注册的服务名。这里的spring.application.name和spring.cloud.config.profile如之前通过URI的方式访问的时候一样,用来定位Git中的资源。
3、在应用主类中,增加@EnableEurekaClient注解,用来发现springcloud-config-server服务,利用其来加载应用配置:
-
@SpringBootApplication
-
@EnableEurekaClient
-
public class SpringcloudConfigClientApplication {
-
public static void main(String[] args) {
-
SpringApplication.run(SpringcloudConfigClientApplication.class, args);
-
}
-
}
4、沿用之前我们创建的Controller来加载Git中的配置信息:
-
@RestController
-
public class TestGetConfigController {
-
@Value("${configFile}")
-
String configFile;
-
@RequestMapping(value = "/configFile")
-
public String getConfigFile(){
-
return configFile;
-
}
-
}
5、完成上述配置之后,我们启动客户端应用。若启动成功,访问http://10.0.45.103:7001/configFile,可以在Eureka Server的信息面板中看到该应用已经被注册成功。
6、访问客户端应用提供的服务 http://10.0.45.103:7001/configFile,此时,我们会返回在Git仓库中application-dev.properties文件中的配置config-filede属性内容:“configFile dev version 1”
失败快速响应与重试
Spring Cloud Config的客户端会预先加载很多其他信息,然后再开始连接Config Serve进行属性的注入。当我们构建的应用较为复杂的时候,可能在连接Config Server之前花较长的启动时间,而在一些特殊场景下,我们又希望可以快速知道当前应用是否能顺利从Config Server获取到配置信息,这对在初期构建调试环境时,可以减少很多等待启动的时间。要实现客户端优先判断Config Server获取是否正常,并快速响应失败内容,只需在bootstrap.properties中配置参数spring.cloud.config.failFast=true即可。
我们可以实现一下,在未配置该参数前,不启动Config Server,直接启动客户端应用,可以获得下面的报错信息。同时,在报错之前,可以看到客户端应用加载了很多内容,比如说Controller的请求等。
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testGetConfigController': Injection of autowired dependencies failed;
加上spring.cloud.config.fail-fast=true 参数之后,在启动客户端应用,可以获取下面的报错信息,并且前置的加载内容少了很多,这样通过该参数有效地避免的了当Congfig Server配置有误时,不需要多等待前置的一些加载时间,实现了快速返回失败信息
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
上面我们演示了当Config Server宕机或是客户端配置不正确导致连接不到而启动失败的情况,快速响应的配置可以发挥比较好的效果。但是,若只是因为网络波动等其他间接性原因导致的问题,直接启动失败似乎代价有点高。所以Config客户端还提供了自动重试的功能,在开启重试功能前,先确保已经配置了spring.cloud.config.failFast=true,在进行下面的操作。
1、在客户端的pom.xml中增加spring-retry和spring-boot-starter-aop依赖,具体如下:
-
<dependency>
-
<groupId>org.springframework.retry</groupId>
-
<artifactId>spring-retry</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-aop</artifactId>
-
</dependency>
2、不需要在做其他任何配置,启动客户端应用,在控制台中可以看到如下内容。客户端在连接Config Server失败之后,会继续尝试,知道第六次失败后才返回错误信息。通过这样的重试机制,可以避免一些间歇性问题引起的失败导致客户端应用无法启动的情况。
-
2018-11-06 14:14:50.752 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:14:52.813 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:14:54.947 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:14:57.188 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:14:59.548 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:15:02.044 INFO 828 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://localhost:8888
-
2018-11-06 14:15:03.084 ERROR 828 --- [ main] o.s.boot.SpringApplication : Application startup failed
-
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
若对默认的最大重试次数和重试间隔等设置不满意,还可以通过下面的参数进行调整。
-
spring.cloud.config.retry.multiplier:初始重试间隔时间(单位为毫秒),默认为1000毫秒。
-
spring.cloud.config.retry.initial-interval:下一间隔的乘数,默认为1.1所以当初间隔是1000毫秒时,下一次失败的间隔为1100毫秒。
-
spring.cloud.config.retry.max-interval:最大间隔时间,默认为2000毫秒。
-
spring.cloud.config.retry.max.attempts:最大重试次数,默认为六次。
获取远程配置
在入门示例中,我们队{application}、{profile}、{lable}这些参数已经有了一定的了解。在Git仓库中,一个形如{application}-{profile}.properties或{application}-{profile}.yml的配置文件,通过URL请求和客户端配置的访问对应可以总结如下:
1、通过向Config Server发送GET请求以直接的方式获取,可用下面的链接形式。
-
不带{label}分支信息,默认访问master分支,可使用:
-
1./{application}-{profile}.yml
-
2./{application}-{profile}-properties
-
带{label}分支信息,可使用:
-
1./{label}/{application}-{profile}.yml
-
2./{application}/{profile}[/{label}]
-
3./{label}/{application}-{profile}.properties
2、通过客户端配置方式加载的内容如下所示。
-
1.spring• application.name:对应配置文件中的{application}内容。
-
2.spring. cloud, config.profile:对应配置文件中{profile}内容。
-
3.spring.cloud.config. label:对应分支内容,如不配置,默认为master。
动态刷新配置
有时候,我们需要对配置内容做一些实时更新,那么Spring Cloud Config是否可以实现呢?答案显然是可以的。下面,我们以快速入门中的示例作为基础,看看如何进行改造来实现配置内容的实时更新。
首先,回顾一下,当前我们已经实现了哪些内容。
1、config-repo:定义在 Git仓库中的一个目录,其中存储了应用名为didispace的多环境配置文件,配置文件中有一个from参数。
2、 config-server:配置了 Git仓库的服务端。
3、config- client:指定了springcloud-config-server为配置中心的客户端,应用名为springcloud-config-client,用来访问配置服务器以获取配置信息。该应用中提供了一个/configFile接口,它会获取 respository/ application-dev.properties 中的 configFile属性返回。
在改造程序之前,我们先将 springcloud-config- server 和 springcloud-config-client 都启动起来,并访问客户端提供的REST接口 http:// localhost:7002/ configFile 来获取配置信息,获得的返回内容为 configFile dev version 1。接着,我们可以尝试使用Git工具修改当前配置的内容,比如, 将 respository/application-dev.properties 中的 configFile 的值从 configFile = configFile dev version 1 修改为 configFile = configFile dev version 2,再访问 http://10.0.45.103:7001/configFile,可以看到其返回内容还是configFile dev version 1。
接下来,我们将在springcloud-config-client端做一些改造以实现配置信息的动态刷新。
1、在springcloud-config-client的pom.xml中新增 spring-boot-starter-actuator 监控模块。其中包含了/refresh端点的实现,该端点将用于应用配置信息的重新获取与刷新。
-
<!--实时刷新配置文件-->
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-actuator</artifactId>
-
</dependency>
2、重新启动 springcloud-config-client,访问一次 http://10.0.45.103:7001/configFile 可以看到当前的配置值。
3、修改Git 仓库 respository/application-dev.properties文件中的值。
4、在访问一次 http://10.0.45.103:7001/configFile ,可以看到配置值没有发生改变。
5、通过POST请求发送到 http://10.0.45.103:7001/refresh,我们可以看到返回内容如下,代表configFile参数的配置内容被更新了:
6、再一次访问 http://10.0.45.103:7001/configFile,可以看到配置值已经是更新后的值了。
通过上面的介绍,大家不难想到,该功能还可以同Git仓库的Web Hook功能进行关联,当有Git提交变化时,就给对应的配置主机发送/refresh请求来实现配置信息的实时更新。但是,当我们的系统发展壮大之后,维护这样的刷新清单也将成为一个非常大的负担,而且很容易犯错,那么有什么办法可以解决这个复杂度呢?后续我们将介绍如何通过 Spring Cloud Bus来实现以消息总线的方式进行配置变更的通知,并完成集群上的批量配置更新。
远程拉取配置文件操作数据库
我们在项目实战中肯定不会像上面的操作一样,我们会把一些常用的配置信息放在github的配置文件中,放入多个环境的配置文件,每个配置文件中会有一些mysql,mybatis,redis,分页,等诸多的配置信息参数,下面我们就来演示从github获取mysql,mybatis的相关配置信息来操作数据库.
1、准备好配置文件的相关信息
-
#mysql相关配置信息
-
spring.datasource.url=jdbc:mysql://10.0.45.103/mysql-test?characterEncoding=utf8
-
spring.datasource.driverClassName=com.mysql.jdbc.Driver
-
spring.datasource.username=root
-
spring.datasource.password=root
-
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
-
spring.datasource.initialSize=5
-
spring.datasource.maxActive=200
-
spring.datasource.minIdle=5
-
spring.datasource.maxWait=60000
-
spring.datasource.timeBetweenEvictionRunsMillis=60000
-
spring.datasource.minEvictableIdleTimeMillis=300000
-
spring.datasource.validationQuery=select 'x'
-
spring.datasource.testWhileIdle=true
-
spring.datasource.testOnReturn=false
-
spring.datasource.poolPreparedStatements=true
-
spring.datasource.maxOpenPreparedStatements=20
-
spring.datasource.testOnBorrow=false
-
#mybatis相关配置信息
-
mybatis.mapper-locations=com/zy/cn/mapper/*.xml
-
mybatis.type-aliases-package=com.zy.cn.entity
2、启动eureka集群项目[上一篇博文中有搭建过程,代码已上传github]
3、启动springcloud-config-server项目[代码已上传github]
4、在客户端建立bootstrap.properties文件,在启动入口类时会首先加载bootstrap.properties中的相关配置信息参数如下:
-
spring.application.name=springcloud-config-client
-
# 对应的文件为application-datasource.properties文件
-
spring.cloud.config.profile=datasource
-
# 指明远程仓库的分支
-
spring.cloud.config.label=master
-
# 配置中心config-server的地址 在configServer分布式配置中心没有在eureka注册中心注册时,指定该ConfigServer的服务器地址通过访问Controller
-
# 来测试客户端获取git仓库的某个文件内容,之后ConfigServer在注册中心进行注册就可以使用service-id属性来指定分布式服务的名称,直接使用分布式服务
-
#spring.cloud.config.uri=http://10.0.45.103:8080/
-
#端口
-
server.port=7001
-
#开启通过服务来访问ConfigServer的功能
-
spring.cloud.config.discovery.enabled=true
-
#指定分布式配置中心服务名称
-
spring.cloud.config.discovery.service-id=springcloud-config-server
-
#将分布式配置中心交给eureka集群注册中心来管理
-
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/,http://peer3:3333/eureka/,http://peer2:2222/eureka/
-
#启动失败时能够快速响应
-
spring.cloud.config.fail-fast=true
-
#关闭刷新安全认证
-
management.security.enabled=false
-
#和重试机制相关的配置有如下四个:
-
# 配置重试次数,默认为6
-
spring.cloud.config.retry.max-attempts=6
-
# 间隔乘数,默认1.1
-
spring.cloud.config.retry.multiplier=1.1
-
# 初始重试间隔时间,默认1000ms
-
spring.cloud.config.retry.initial-interval=1000
-
# 最大间隔时间,默认2000ms
-
spring.cloud.config.retry.max-interval=2000
5、创建DataSourceProperties.class 作用就是通过@ConfigurationProperties注解实现了配置信息的注入,该注解的作用:当以@ConfigurationProperties这种方式注册bean时,该bean具有常规名称:<prefix>-<fqn>,属性 //其中<prefix>是在@ConfigurationProperties注释中指定的环境[系统环境]键前缀,并且<fqn>是bean的完全限定名称。 //如果注释没有提供任何前缀,则只使用bean的完全限定名称。系统环境就是已经加载bootstrap.properties文件从远程github仓库获取相关信息通过@ConfigurationProperties 注解给DataSourceProperties的属性进行参数绑定。
-
/**
-
* 该类配置数据源相关属性
-
* 从springcloud config远程github获取配置文件信息
-
*/
-
//https://www.breakyizhan.com/springboot/3287.html Springboot中文文档24.7
-
//当以@ConfigurationProperties这种方式注册bean时,该bean具有常规名称:<prefix>-<fqn>,睡醒
-
//其中<prefix>是在@ConfigurationProperties注释中指定的环境[系统环境]键前缀,并且<fqn>是bean的完全限定名称。
-
//如果注释没有提供任何前缀,则只使用bean的完全限定名称。
-
//通过使用@ConfigurationProperties注解实现了配置信息的注入;
-
// 然后又通过使用@EnableConfigurationProperties注解才使得配置bean被创建出来
-
@ConfigurationProperties(prefix = DataSourceProperties.PREFIX, ignoreUnknownFields = false)
-
public class DataSourceProperties {
-
public DataSourceProperties() {
-
super();
-
}
-
//定义前缀 //对应远程配置文件里的key
-
public final static String PREFIX = "spring.datasource";
-
private String type;
-
private String driverClassName;
-
private String url;
-
private String username;
-
private String password;
-
private int maxActive = 1000;
-
private int maxIdle = 100;
-
private int minIdle = 8;
-
private int initialSize = 10;
-
private int maxWait;
-
private int timeBetweenEvictionRunsMillis;
-
private int minEvictableIdleTimeMillis;
-
private String validationQuery;
-
private boolean testWhileIdle;
-
private boolean poolPreparedStatements;
-
private int maxOpenPreparedStatements;
-
private boolean testOnBorrow = true;
-
private boolean testOnReturn = false;
-
//提供get/set方法
-
}
6、创建MybatisSourceProperties.class文件
-
//@ConfigurationProperties 标注的“已经存在”的 bean 都会从系统环境中加载配置信息
-
@ConfigurationProperties(prefix = MybatisSourceProperties.PREFIX, ignoreUnknownFields = false)
-
//通过使用@ConfigurationProperties注解实现了配置信息的注入;
-
// 然后又通过使用@EnableConfigurationProperties注解才使得配置bean被创建出来
-
public class MybatisSourceProperties {
-
//指定远程配置文件前缀
-
public final static String PREFIX = "mybatis";
-
//mapper配置文件位置
-
private String mapperLocations;
-
//实体的别名
-
private String typeAliasesPackage;
-
//并提供get/set方法
-
}
7、在入口类上该注解上加参数 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}),意思就是将spring boot自带的DataSourceAutoConfiguration禁掉,防止自动配置数据源
-
@MapperScan("com.zy.cn.dao")
-
@EnableEurekaClient
-
//将spring boot自带的DataSourceAutoConfiguration禁掉,防止自动配置数据源
-
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
-
public class SpringcloudProviderApplication {
-
public static void main(String[] args) {
-
SpringApplication.run(SpringcloudProviderApplication.class, args);
-
}
-
}
8、自定义数据源 MybatisDataSource.class文件 ,该文件中创建数据源组件,创建SqlSessionFactory,创建事物管理器,在这里注意:通过使用@ConfigurationProperties注解实现了配置信息的注入,然后又通过使用@EnableConfigurationProperties注解才使得配置bean被创建出来。
-
@Configuration
-
@MapperScan("com.zy.cn.*")
-
//加载数据源以及mybatis的相关配置信息
-
@EnableConfigurationProperties({DataSourceProperties.class,MybatisSourceProperties.class})
-
//通过使用@ConfigurationProperties注解实现了配置信息的注入;
-
// 然后又通过使用@EnableConfigurationProperties注解才使得配置bean被创建出来
-
@EnableTransactionManagement//事务管理器
-
public class MybatisDataSource {
-
@Autowired
-
private DataSourceProperties dataSourceProperties;
-
@Autowired
-
private MybatisSourceProperties mybatisSourceProperties;
-
private DruidDataSource datasource = null;
-
//创建数据源组件
-
@Bean(destroyMethod = "close")
-
public DataSource dataSource(){
-
datasource = new DruidDataSource();
-
//注入连接数据库的·url地址
-
datasource.setUrl(dataSourceProperties.getUrl());
-
//注入类型
-
datasource.setDbType(dataSourceProperties.getType());
-
datasource.setDriverClassName(dataSourceProperties.getDriverClassName());
-
//注入用户名密码
-
datasource.setUsername(dataSourceProperties.getUsername());
-
datasource.setPassword(dataSourceProperties.getPassword());
-
//连接相关配置参数
-
datasource.setInitialSize(dataSourceProperties.getInitialSize());
-
datasource.setMaxActive(dataSourceProperties.getMaxActive());
-
datasource.setMinIdle(dataSourceProperties.getMinIdle());
-
datasource.setMaxWait(dataSourceProperties.getMaxWait());
-
datasource.setTimeBetweenEvictionRunsMillis(dataSourceProperties.getTimeBetweenEvictionRunsMillis());
-
datasource.setValidationQuery(dataSourceProperties.getValidationQuery());
-
datasource.setTestWhileIdle(dataSourceProperties.getTestWhileIdle());
-
datasource.setTestOnReturn(dataSourceProperties.isTestOnReturn());
-
datasource.setTestOnBorrow(dataSourceProperties.isTestOnBorrow());
-
datasource.setPoolPreparedStatements(dataSourceProperties.getPoolPreparedStatements());
-
datasource.setMaxOpenPreparedStatements(dataSourceProperties.getMaxOpenPreparedStatements());
-
return datasource;
-
}
-
@PreDestroy
-
public void close() {
-
if(datasource != null){
-
//关闭数据源
-
datasource.close();
-
}
-
}
-
//创建sqlSessionFactory连接对象
-
@Bean
-
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
-
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
-
//注入数据源组件
-
sqlSessionFactoryBean.setDataSource(dataSource());
-
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
-
//mybatis的mapper配置文件位置
-
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mybatisSourceProperties.getMapperLocations()));
-
//指定实体别名的位置
-
sqlSessionFactoryBean.setTypeAliasesPackage(mybatisSourceProperties.getTypeAliasesPackage());
-
return sqlSessionFactoryBean.getObject();
-
}
-
//创建事务管理器
-
@Bean
-
public PlatformTransactionManager transactionManager() {
-
//注入数据源对象
-
return new DataSourceTransactionManager(dataSource());
-
}
-
}
9.创建mapper配置文件
10.进行测试,测试成功说明从github远端获取配置信息进行加载从而进行操作数据库。这样子也是方便对各个环境的尽快地做出改变不需要人为的进行管理。