Spring Cloud 配置中心 Consul 入门
1. 概述
在《Consul 极简入门》文章中,我们一起完成了 Consul 的学习,并完成了 Consul 服务器的搭建。
本文我们来学习 Spring Cloud Consul 提供的 spring-cloud-consul-config
组件,接入 Consul 作为配置中心,实现服务的统一配置管理。
2. 快速入门
示例代码对应仓库:
labx-28-sc-consul-config-demo
。
本小节,我们会在 Consul 服务中定义配置,并使用 @ConfigurationProperties
和 @Value
注解,读取该配置。
友情提示:如果胖友看过《Spring Boot 配置文件入门》的「2. 自定义配置」小节,就会发现本小节是对标这块的内容。
下面,我们来创建一个 labx-28-sc-consul-config-demo
示例项目,进行快速入门。最终项目代码如下图所示:
2.1 引入依赖
在 pom.xml
文件中,主要引入 Spring Cloud Consul Config 相关依赖。代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-28</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-28-sc-consul-config-demo</artifactId>
<properties>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Consul Config 相关依赖,将 Consul 作为配置中心,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
</dependencies>
</project>
引入 spring-cloud-starter-consul-config
依赖,将 Consul 作为配置中心,并实现对它的自动配置。
2.2 配置文件
创建 bootstrap.yaml
配置文件,添加 Consul Config 配置项。配置如下:
spring:
application:
name: demo-application
cloud:
# Spring Cloud Consul 通用配置项,对应 ConsulProperties 类
consul:
host: 127.0.0.1 # Consul 主机
port: 8500 # Consul 端口
# Spring Cloud Consul Config 配置项,对应 ConsulConfigProperties 类
config:
format: YAML # Consul 配置的格式
prefix: config # Consul 配置的目录
data-key: data # Consul 配置的文件
profile-separator: ',' # 多环境目录分隔符,默认为 ,
① spring.cloud.consul
配置项,设置 Consul 客户端的配置,对应 ConsulProperties 配置类。
通过 host
和 port
配置项,设置 Consul 服务器的地址。
② spring.cloud.consul.config
配置项,设置 Consul Config 配置项,对应 ConsulConfigProperties 配置类。
通过 prefix
、data-key
、format
配置项,设置读取的 Consul 服务中的配置地址和格式。如下图所示:
- 注意,读取 Consul 服务中的配置地址是
{prefix}/{spring.application.name}/{data-key}
,因此本小节的示例是config/demo-application/data
profile-separator
配置项,多环境目录分隔符,默认为 ,
。举个例子,在我们设置 Spring Profile 为 dev
时,会多读取 Consul 服务中的配置地址是 {prefix}/{spring.application.name},dev/{data-key}
,作为配置项。
2.3 创建 Consul 配置项
打开 Consul 运维界面,创建 config/demo-application/data
配置 Key,并设置配置 Value 如下:
order:
pay-timeout-seconds: 60
create-frequency-seconds: 120
2.4 OrderProperties
创建 OrderProperties 配置类,读取 order
配置项。代码如下:
@Component
@ConfigurationProperties(prefix = "order")
public class OrderProperties {
/**
* 订单支付超时时长,单位:秒。
*/
private Integer payTimeoutSeconds;
/**
* 订单创建频率,单位:秒
*/
private Integer createFrequencySeconds;
// ... 省略 setter/getter 方法
}
① 在类上,添加 @Component
注解,保证该配置类可以作为一个 Bean 被扫描到。
② 在类上,添加 @ConfigurationProperties
注解,并设置 prefix = "order"
属性,这样它就可以读取前缀为 order
配置项,设置到配置类对应的属性上。
2.5 DemoController
创建 DemoController 类,提供测试 @ConfigurationProperties
和 @Value
注入配置的两个 HTTP 接口。代码如下:
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private OrderProperties orderProperties;
/**
* 测试 @ConfigurationProperties 注解的配置属性类
*/
@GetMapping("/test01")
public OrderProperties test01() {
return orderProperties;
}
@Value(value = "${order.pay-timeout-seconds}") // @NacosValue(value = "${order.pay-timeout-seconds}")
private Integer payTimeoutSeconds;
@Value(value = "${order.create-frequency-seconds}") // @NacosValue(value = "${order.create-frequency-seconds}")
private Integer createFrequencySeconds;
/**
* 测试 @Value 注解的属性
*/
@GetMapping("/test02")
public Map<String, Object> test02() {
return new JSONObject().fluentPut("payTimeoutSeconds", payTimeoutSeconds)
.fluentPut("createFrequencySeconds", createFrequencySeconds);
}
}
2.6 DemoApplication
创建 DemoApplication 类,作为应用启动类。代码如下:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class);
}
}
2.7 简单测试
① 使用 DemoApplication 启动示例应用。在 IDEA 控制台中,可以看到 Consul 相关的日志如下:
// 加载了 Consul 服务中的配置 Key `/config/demo-application/data` 和 `/config/application/dadta`,作为配置项
2020-06-12 08:01:32.263 INFO 82286 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-config/demo-application/'}, BootstrapPropertySource {name='bootstrapProperties-config/application/'}]
友情提示:Consul Config 会额外加载 Consul 服务中的配置 Key
/config/application/data
,实现多应用之间的配置共享。
② 使用浏览器,访问 http://127.0.0.1:8080/demo/test01 接口,测试 @ConfigurationProperties
注解的配置属性类,返回结果如下,符合预期:
{
"payTimeoutSeconds": 60,
"createFrequencySeconds": 120
}
② 使用浏览器,访问 http://127.0.0.1:8080/demo/test02 接口,测试 @Value
注解的属性,返回结果如下,符合预期:
{
"payTimeoutSeconds": 60,
"createFrequencySeconds": 120
}
3. 多环境配置
示例代码对应仓库:
labx-28-sc-consul-config-demo
。
在《芋道 Spring Boot 配置文件入门》的「6. 多环境配置」中,我们介绍如何基于 spring.profiles.active
配置项,在 Spring Boot 实现多环境的配置功能。
在本文的「2. 快速入门」小节中,我们已经提到,Spring Cloud Consul Config 在我们设置了 Spring Profile 的值时,会多读取 Consul 服务中的配置地址是 {prefix}/{spring.application.name},{spring.profiles.active}/{data-key}
,作为配置项。
下面,我们来演示 Consul Config 的多环境配置的功能。无需重新搭建,直接复用「2. 快速入门」小节的项目即可。
3.1 创建 Consul 配置项
① 创建用于 Profile 为 dev
环境的 Consul 服务中的配置地址是 config/demo-application,dev/data
,并创建 server.port
节点的值为 8081。如下图所示:
② 创建用于 Profile 为 prod
环境的 Consul 服务中的配置地址是 config/demo-application,prod/data
,并创建 server.port
节点的值为 8084。如下图所示:
这两配置都有 server.port
配置项,用于启动不同端口的服务器。???? 为什么选择 server.port
配置呢?因为 Spring Cloud 项目启动后,从日志中就可以看到生效的服务器端口,嘿嘿~
3.2 简单测试
② 开发环境示例:直接在 IDEA 中,增加 --spring.profiles.active=dev
到 Program arguments 中。如下图所示:
使用 DemoApplication 应用,输出日志如下:
# 省略其它日志...
// 加载了 Consul 如下地址的配置
// 1. `/config/demo-application,dev/data`
// 2. `/config/demo-application/data`
// 3. `/config/application,dev/data`
// 4. `/config/application/data`
2020-06-12 08:37:11.521 INFO 83147 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-config/demo-application,dev/'}, BootstrapPropertySource {name='bootstrapProperties-config/demo-application/'}, BootstrapPropertySource {name='bootstrapProperties-config/application,dev/'}, BootstrapPropertySource {name='bootstrapProperties-config/application/'}]
# Tomcat 启动日志
2020-06-12 08:37:12.454 INFO 83147 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
Tomcat 启动在 8081 端口,也符合 dev
环境读取 Consul /config/demo-application,dev/data
地址下的配置。
③ 生产环境示例:直接在 IDEA 中,增加 --spring.profiles.active=prod
到 Program arguments 中。如下图所示:
使用 DemoApplication 应用,输出日志如下:
# 省略其它日志...
// 加载了 Consul 如下目录的配置
// 1. `/config/demo-application,prod/data`
// 2. `/config/demo-application/data`
// 3. `/config/application,prod/data`
// 3. `/config/application/data`
2020-06-12 08:39:07.123 INFO 83230 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-config/demo-application,prod/'}, BootstrapPropertySource {name='bootstrapProperties-config/demo-application/'}, BootstrapPropertySource {name='bootstrapProperties-config/application,prod/'}, BootstrapPropertySource {name='bootstrapProperties-config/application/'}]
# Tomcat 启动日志
2020-06-12 08:40:29.769 INFO 83258 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8084 (http) with context path ''
Tomcat 启动在 8084 端口,也符合 prod
环境读取 Consul /config/demo-application,prod/data
地址下的配置。
4. 自动刷新配置
示例代码对应仓库:
labx-28-sc-consul-config-auto-refresh
。
在上面的示例中,我们已经实现从 Consul 读取配置。那么,在应用已经启动的情况下,如果我们将读取的 Consul 的配置进行修改时,应用是否会自动刷新本地的配置呢?
如果是我们上面的示例,答案是部分会。使用 @ConfigurationProperties
注解的会,使用 @Value
注解的不会。
下面,我们从「2. 快速入门」小节的 labx-28-sc-consul-config-demo
项目,复制出 labx-28-sc-consul-config-auto-refresh
项目,用于演示 Consul 的自动刷新配置的功能。最终项目代码如下图所示:
4.1 简单测试
① 使用 DemoApplication 启动示例应用。
② 获得 Consul 的 /config/demo-application/config
地址的配置内容为:
order:
pay-timeout-seconds: 60 # 订单支付超时时长,单位:秒。
create-frequency-seconds: 120 # 订单创建频率,单位:秒
使用 curl
命令,请求 DemoController 提供的两个测试接口,过程如下:
# 测试 `@ConfigurationProperties` 注解的配置属性类
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":120}
# 测试 `@Value` 注解的属性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":120}
③ 修改 Consul 的 /config/demo-application/config
地址的配置内容为:
order:
pay-timeout-seconds: 60 # 订单支付超时时长,单位:秒。
create-frequency-seconds: 480 # 订单创建频率,单位:秒
此时,我们可以看到 IDEA 控制台打印出了 order.create-frequency-seconds
配置项发生变化的日志,内容如下:
2020-06-12 08:54:40.052 INFO 83728 --- [TaskScheduler-1] o.s.c.e.event.RefreshEventListener : Refresh keys changed: [order.create-frequency-seconds]
使用 curl
命令,请求 DemoController 提供的两个测试接口,过程如下:
# 测试 `@ConfigurationProperties` 注解的配置属性类
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":480}
# 测试 `@Value` 注解的属性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":120}
- 使用
@ConfigurationProperties
注解的成功刷新,使用@Value
注解的失败刷新。
4.2 @RefreshScope
在 Spring Cloud 中,提供了 @RefreshScope
注解,可以声明在 Bean 上,实现该 Bean 的配置刷新。
友情提示:对
@RefreshScope
注解的实现原理感兴趣的胖友,可以阅读《@RefreshScope 那些事》文章。
下面,我们将 @RefreshScope
注解添加在 DemoController 类上,实现 @Value
注解的属性的刷新。代码如下:
@RestController
@RequestMapping("/demo")
@RefreshScope // 加我加我加我!
public class DemoController {
// ... 省略其它代码
}
4.3 重新测试
① 使用 DemoApplication 启动示例应用。
② 获得 Consul 的 /config/demo-application/config
地址的配置内容为:
order:
pay-timeout-seconds: 60 # 订单支付超时时长,单位:秒。
create-frequency-seconds: 480 # 订单创建频率,单位:秒
使用 curl
命令,请求 DemoController 提供的两个测试接口,过程如下:
# 测试 `@ConfigurationProperties` 注解的配置属性类
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":480}
# 测试 `@Value` 注解的属性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":480}
③ 修改 Consul 的 /config/demo-application/config
地址的配置内容为:
order:
pay-timeout-seconds: 60 # 订单支付超时时长,单位:秒。
create-frequency-seconds: 960 # 订单创建频率,单位:秒
使用 curl
命令,请求 DemoController 提供的两个测试接口,过程如下:
# 测试 `@ConfigurationProperties` 注解的配置属性类
$ curl http://127.0.0.1:8080/demo/test01
{"payTimeoutSeconds":60,"createFrequencySeconds":960}
# 测试 `@Value` 注解的属性
$ curl http://127.0.0.1:8080/demo/test02
{"payTimeoutSeconds":60,"createFrequencySeconds":960}
- 使用
@ConfigurationProperties
注解的成功刷新,使用@Value
注解的成功刷新。完美~
4.4 EnvironmentChangeEvent
通过 @ConfigurationProperties
或者 @Value
+ @RefreshScope
注解,已经能够满足我们绝大多数场景下的自动刷新配置的功能。但是,在一些场景下,我们仍然需要实现对配置的监听,执行自定义的逻辑。
例如说,当数据库连接的配置发生变更时,我们需要通过监听该配置的变更,重新初始化应用中的数据库连接,从而访问到新的数据库地址。
又例如说,当日志级别发生变更时,我们需要通过监听该配置的变更,设置应用中的 Logger 的日志级别,从而后续的日志打印可以根据新的日志级别。
在 Spring Cloud 中,在 Environment 的属性配置发生变化时,会发布 EnvironmentChangeEvent 事件。这样,我们只需要实现 EnvironmentChangeEvent 事件的监听器,就可以进行自定义的逻辑处理。
例如说,Spring Cloud 内置了 LoggingRebinder 监听器,实现了对 EnvironmentChangeEvent 事件的监听,在发现 logging.level
配置项发生变化时,重新设置日志组件的日志级别。如下图所示:
下面,我们来实现一个自定义的 DemoEnvironmentChangeListener 监听器,打印下变化配置项的最新值。代码如下:
@Component
public class DemoEnvironmentChangeListener implements ApplicationListener<EnvironmentChangeEvent> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ConfigurableEnvironment environment;
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
for (String key : event.getKeys()) {
logger.info("[onApplicationEvent][key({}) 最新 value 为 {}]", key, environment.getProperty(key));
}
}
}
补充:最近看了下文档,可以通过
@RefreshScope
注解,实现数据源的动态变化,具体可以看看《SpringCloud 运行时刷新数据源相关配置》文章。也就是说,不一定需要通过实现对 EnvironmentChangeEvent 事件的监听处理。
4.5 再次测试
① 使用 DemoApplication 启动示例应用。
② 修改 Consul 的 /config/demo-application/config
地址的配置内容,增加 test
配置项为 true
。此时在 IDEA 控制台可以看到 DemoEnvironmentChangeListener 打印的日志如下:
2020-06-12 09:00:51.373 INFO 83728 --- [TaskScheduler-1] .i.s.l.c.l.DemoEnvironmentChangeListener : [onApplicationEvent][key(test) 最新 value 为 true]
5. 配置加密
考虑到安全性,我们可能最好将配置文件中的敏感信息进行加密。例如说,MySQL 的用户名密码、第三方平台的 Token 令牌等等。不过,Consul Config 暂时未内置配置加密的功能。官方文档说明如下:
因此,我们暂时只能在客户端进行配置的加解密。这里,我们继续采用在《Spring Boot 配置文件入门》的「8. 配置加密」小节中使用的 Jasypt。
至此,我们已经完成 Spring Cloud Consul 作为配置中心的学习。如下是 Consul Config 相关的官方文档:
上一篇: PHP 开发工具_php文摘
推荐阅读
-
spring cloud config 配置中心快速实现过程解析
-
详解Spring Cloud Feign 熔断配置的一些小坑
-
spring cloud实现Eureka注册中心的HA的方法
-
跟我学SpringCloud | 第六篇:Spring Cloud Config Github配置中心
-
详解Spring Cloud Consul 实现服务注册和发现
-
Spring Cloud Config实现分布式配置中心
-
Spring cloud Eureka注册中心搭建的方法
-
Spring Cloud动态配置实现原理与源码分析
-
Spring-Cloud Eureka注册中心实现高可用搭建
-
Spring Cloud入门程序