前言
最近在一直在学习Spring Cloud 相关的基础组件, 本篇文章我将用一个实际的Demo来记录一下如何使用 Spring Cloud Config 将服务配置与服务代码本身分离。
项目地址: spring-cloud-config-demo
自打盘古开天地以来, 我们就一直被灌输不要将硬编码写入应用程序代码中的观念。所以通常情况下每一个项目都会使用一个公共的常量类或者配置文件来存储应用的相关配置信息, 在应用程序少量的情况下这样做是没有问题的, 但是在处理可能包含数十个甚至数百个基于微服务的应用程序时,仍然采用原始的方法就显得力不从心了。
所以在微服务的场景下, 配置管理就变成了一件需要认真考虑的大事(一直都是大事),一般强调为以下几点:
1. 应用程序的配置与正在部署的实际代码完全分离
2.将代码部署到不同的服务器上时配置文件应该是统一的
3.在服务启动时通过环境变量注入配置,或通过集中式存储库读取应用程序配置
4.将配置信息与实际代码分开后,应当建立一个能够对配置文件进行管理和版本控制的外部依赖项(git, svn等)
以下引用 spring microservices in action 书中原文来进一步说明
- 分离 - 我们希望将服务配置信息与服务的实际物理部署完全分开。应用程序配置不应与服务实例一起部署。相反,配置信息应该作为环境变量传递给正在启动的服务,或者在服务启动时从集中式存储库中读取。
- 抽象 - 将访问配置数据的功能抽象到一个服务接口中。应用程序使用基于REST的JSON服务来检索配置数据,而不是编写直接访问服务存储库的代码(也就是从文件或者JDBC从数据库中读取数据)。
- 集中 - 因为基于云的应用程序可能会有数百个服务,所以最小化用于保存配置信息的不同存储库的数量至关重要。将应用程序配置集中在尽可能少的存储库中。
- 稳定 - 因为应用程序的配置信息与部署的服务完全隔离并集中存放,所以不管采用何种方案实现,至关重要的一点就是保证其高可用和冗余。
下图更加详细的介绍了配置文件引导的过程
图片来自 spring microservices in action 一书
具体实现
幸运的是 Spring Cloud Config 已经帮我们做了大部分的事情, 在实际使用中我们只需要做一些简单的配置就可以迅速的搭建起一个基于微服务的配置管理服务。
Spring Cloud Config 是基于REST的应用程序, 它建立在 Spring Boot 之上, 我们需要将他嵌入到 Spring Boot 应用程序中。下面我将分别以配置服务器(config-server)与应用程序(config-client)的角度来分别介绍一下整合
Spring Cloud Config 的过程。
1. 搭建配置管理服务(config-server)
创建 Spring Boot 应用并加入相关依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
如上所示,除了配置服务的依赖以外,还额外添加了 security 的相关依赖。该依赖可以用来保护我们的配置管理服务, 这里我们采用最简单的 Http Basic 验证来认证客户端的请求,当然你也可以采用其他的认证方式,在 官方文档 中都有详细的介绍,这里就不再赘述。
在程序引导类上添加相应注解
@SpringBootApplication
@EnableConfigServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
@EnableConfigServer 将标记该应用程序为一个配置管理服务
配置应用程序相关信息
这里的配置文件采用了两种方式 application.yml 与 bootstrap.yml, 这两种配置文件的区别可以参考这篇文章。
Spring Cloud Config 支持多种配置文件的存储方式(Environment Repository), 具体可参考官方文档 , 这里我使用最简单的文件存储来演示。
application.yml
server:
port: 7016
servlet:
context-path: /server
spring:
profiles:
# 使用本地文件存储
active: native
# 配置安全相关
security:
user:
name: admin
password: secret
cloud:
config:
server:
native:
# 指定配置文件位置
search-locations:
- classpath:/config/configclient
bootstrap.yml
spring:
application:
name: configserver
如上的 security 配置项配置了连接配置服务需要的用户名与密码,在之后的应用程序中我们将使用这两项参数。
- 在 resources 目录下新建指定应用程序的配置
注意配置文件的命名格式为 应用名称 + - + 环境, 这里的环境将根据应用程序配置文件中的如下配置动态的进行选择。
spring:
profiles:
active: dev
至此我们的配置管理服务就搭建完毕。
2. 搭建应用程序服务(config-client)
创建 Spring Boot 应用并加入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
如上所示,应用程序服务就是个简单的 SpringBoot 项目, 额外添加了 Spring Retry 来支持Spring Cloud Config 的重试机制。
配置应用程序相关信息
application.yml
server:
port: 7017
servlet:
context-path: /client
custom:
example: 'asdfasdf'
bootstrap.yml
spring:
application:
name: configclient
profiles:
active: prod
cloud:
config:
# 配置服务地址
uri: http://localhost:7016/server
# 配置验证
username: admin
password: secret
# 开启重试
fail-fast: true
# 配置重试策咯参数
retry:
initial-interval: 5000
maxInterval: 10000
maxAttempts: 10
这里需要注意的是 Spring Cloud Config 相关的配置只能配置在 bootstrap.yml 文件中, 因为该配置文件会优先于 application.yml 加载,处于程序上下文的引导阶段。
至此我们的应用程序服务就搭建完毕了, 访问 http://127.0.0.1/client/configs 即可看到我们在配置管理服务中配置的参数了。
最后的想法
应用程序的配置可能听起来普普通通, 但它在微服务的场景中至关重要。在基于云的环境中应用程序配置数据应该与应用程序完全分离,并在运行时注入相应的配置数据。