技术背景
如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每个项目都散落着各种配置文件,且随着服务的增加而不断增多。此时,往往某一个基础服务信息变更,都会导致一系列服务的更新和重启,运维也是苦不堪言,而且还很容易出错。于是,配置中心便由此应运而生了。
目前市面上开源的配置中心有很多,像Spring家族的Spring Cloud Config, Apache的Apache Commons Configuration,淘宝的diamond, 百度的disconf, 360的QConf等等,都是为了解决这类问题。当下Spring体系大行其道,我们当然也优先选择Spring Cloud Config了。
Spring Cloud Config
Spring Cloud Config 是一套为分布式系统中的基础设施和微服务应用提供集中化配置的管理方案,它分为服务端与客户端两个部分。服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息。客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理服务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。
Spring Cloud Config对服务端和客户端中的环境变量和属性配置 实现了抽象映射,所以它除了适用于 Spring 应用,也是可以在任何其他语言应用中使用的。Spring Cloud Config 实现的配置中心默认采用 Git 来存储配置信息,所以使用 Spring Cloud Config 构建的配置服务器,天然就支持对微服务应用配置信息的版本管理,并且可以通过 Git 客户端工具非常方便的管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如:SVN 仓库、本地化文件系统等。
实现案例
准备配置文件
首先在GIT下,新建config-reposity目录,用来存放配置文件,如下图所示,分别模拟了三个环境的配置文件。
分别编辑三个文件的,配置 spring.config.hello 属性的值为 hello, this x env configurations.
服务端实现
新建工程
新建 spring-cloud-conifg-server 工程。
添加依赖
除了Spring Cloud依赖之外,添加配置中心依赖包。
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
启动类
启动类添加注解 @EnableConfigServer,开启配置服务支持。
ConfigServerApplication.java
package com.louis.spring.cloud.config.server; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication { public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
添加配置
修改配置文件,添加如下内容。如果是私有仓库需要填写用户名密码,如果是公开仓库,可以不配置密码。
application.yml
server:
port:
spring:
application:
name: spring-cloud-config-server
cloud:
config:
server:
git:
uri: https://gitee.com/liuge1988/spring-cloud-demo/ # 配置git仓库的地址
search-paths: config-repository # git仓库地址下的相对地址,可以配置多个,用,分割。
username: username # git仓库的账号
password: password # git仓库的密码
Spring Cloud Config也提供本地存储配置的方式,只需设置属性spring.profiles.active=native
,Config Server会默认从应用的src/main/resource
目录下检索配置文件。另外也可以通过spring.cloud.config.server.native.searchLocations=file:D:/properties/
属性来指定配置文件的位置。虽然Spring Cloud Config提供了这样的功能,但是为了更好的支持内容管理和版本控制,还是比较推荐使用GIT的方式。
测试效果
启动应用,访问 http://localhost:8551/spring-config/dev,返回结果如下。
启动应用,访问 http://localhost:8551/spring-config/pro,返回结果如下。
上述的返回的信息包含了配置文件的位置、版本、配置文件的名称以及配置文件中的具体内容,说明server端已经成功获取了git仓库的配置信息。
访问:http://localhost:8551/spring-config-dev.properties,返回结果如下。
修改一下dev配置文件内容如下(末尾加了一个 update):
spring.config.hello=hello, this dev env configurations update.
再次访问:http://localhost:8551/spring-config-dev.properties,返回结果如下。
发现读取的是修改后提交的信息,说明服务端会自动读取最新提交的数据。
仓库中的配置文件会被转换成相应的WEB接口,访问可以参照以下的规则:
- /{application}/{profile}[/{label}]
- /{application}-{profile}.yml
- /{label}/{application}-{profile}.yml
- /{application}-{profile}.properties
- /{label}/{application}-{profile}.properties
以spring-config-dev.properties为例子,它的application是spring-config,profile是dev。client会根据填写的参数来选择读取对应的配置。
客户端实现
新建工程
新建 spring-cloud-conifg-client 工程。
添加依赖
添加相关依赖,添加WEB是为了测试接口。
pom.xml
<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>
</dependencies>
添加配置
添加两个配置文件如下。
application.yml
server:
port:
spring:
application:
name: spring-cloud-config-client
bootstrap.yml
spring:
cloud:
config:
uri: http://localhost:8551/ # 配置中心的具体地址
name: spring-config # 对应{application}部分
profile: dev # 对应{profile}部分
label: master # 对应git的分支,如果配置中心使用的是本地存储,则该参数无用
配置说明:
- spring.cloud.config.uri:配置中心的具体地址
- spring.cloud.config.name:对应{application}部分
- spring.cloud.config.profile:对应{profile}部分
- spring.cloud.config.label:对应git的分支。如果配置中心使用的是本地存储,则该参数无用
- spring.cloud.config.discovery.service-id:指定配置中心的service-id,便于扩展为高可用配置集群。
特别注意:
上面这些与spring cloud相关的属性必须配置在bootstrap.yml中,这样config部分内容才能被正确加载。
因为config的相关配置会先于application.yml,而bootstrap.yml的加载也是先于application.yml文件的。
启动类
启动类无需添加额外注解。
ConfigClientApplication.java
package com.louis.spring.cloud.config.client; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class ConfigClientApplication { public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
控制器
添加一个 HelloController 控制器, 添加注解 @Value("${spring.config.hello}"),声明hello属性从配置文件读取。
HelloController.java
package com.louis.spring.cloud.config.client.controller; import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
class HelloController { @Value("${spring.config.hello}")
private String hello; @RequestMapping("/hello")
public String from() {
return this.hello;
}
}
测试效果
先后启动配置中心服务端和客户端, 访问 http://localhost:8552/hello,效果如下。
说明客户端已经成功从服务端读取了配置信息。
现在手动修改一下仓库配置文件的内容,末尾加个数字 2,修改完成并提交。
再次访问 http://localhost:8552/hello,效果如下。
我们发现返回结果并没有读取最新提交的内容,这是因为Spring Boot项目只有在启动的时候才会获取配置文件的内容,虽然GIT配置信息被修改了,但是客户端并没有重新去获取,所以导致读取的信息仍然是旧配置。那么该如何去解决这个问题呢?这就是我们下一章要讲的 Spring Cloud Bus。
配置中心服务化
到目前为止,我们的客户端都是直接调用配置中心的server端来获取配置文件信息。这样客户端和服务端的耦合性太高,如果server端要做集群,客户端只能通过原始的方式来路由,server端改变IP地址的时候,客户端也需要修改配置,不符合Spring Cloud服务治理的理念。所以我们需要将服务端也当做一个服务注册到注册中心,客户端去注册中心获取配置中心服务就可以了。
打开 spring-cloud-conifg-server,修改服务端POM,添加注册中心依赖。
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
启动类添加注解 @EnableDiscoveryClient,提供服务发现支持。
ConfigServerApplication.java
package com.louis.spring.cloud.config.server; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigServerApplication { public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
修改配置,添加服务注册信息。
application.yml
server:
port:
spring:
application:
name: spring-cloud-config-server
cloud:
consul:
host: localhost
port:
discovery:
serviceName: ${spring.application.name} # 注册到consul的服务名称
config:
server:
git:
uri: https://gitee.com/liuge1988/spring-cloud-demo/ # 配置git仓库的地址
search-paths: config-repository # git仓库地址下的相对地址,可以配置多个,用,分割。
username: username # git仓库的账号
password: password # git仓库的密码
先后启动注册中心服务器,配置中心服务器, 访问 http://localhost:8500,确认注册中心注册成功。
访问 http://localhost:8551/config-server/dev,也能成功读取配置,服务端就算改造好了。
打开 spring-cloud-conifg-client,修改服务端POM,添加注册中心依赖。
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
启动类添加注解 @EnableDiscoveryClient,提供服务发现支持。
ConfigClientApplication.java
package com.louis.spring.cloud.config.client; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient
@SpringBootApplication
public class ConfigClientApplication { public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
修改配置文件,移除uri的直接地址配置,开启服务发现并配置serviceId为注册中心服务器的服务名称。
bootstrap.yml
spring:
cloud:
consul:
host: localhost
port:
discovery:
serviceName: spring-cloud-config-client # 注册到consul的服务名称
config:
discovery:
enabled: true # 开启服务发现
serviceId: spring-cloud-config-server # 配置中心服务名称
name: spring-config # 对应{application}部分
profile: dev # 对应{profile}部分
label: master # 对应git的分支,如果配置中心使用的是本地存储,则该参数无用
启动客户端,访问 http://localhost:8552/hello,成功读取配置信息,说明客户端也改造完成了。
源码下载
码云:https://gitee.com/liuge1988/spring-cloud-demo.git
作者:朝雨忆轻尘
出处:https://www.cnblogs.com/xifengxiaoma/
版权所有,欢迎转载,转载请注明原文作者及出处。