Spring Cloud 配置中心 Consul 入门

25 篇文章 2 订阅
10 篇文章 3 订阅

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 示例项目,进行快速入门。最终项目代码如下图所示:

`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 配置类。

通过 prefixdata-keyformat 配置项,设置读取的 Consul 服务中的配置地址和格式。如下图所示:

`labx-28-sc-consul-config-demo` 项目

  • 注意,读取 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

Consul 配置项

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。如下图所示:

`config/demo-application,dev/data` 地址

② 创建用于 Profile 为 prod 环境的 Consul 服务中的配置地址是 config/demo-application,prod/data,并创建 server.port 节点的值为 8084。如下图所示:

`/config/demo-application,prod/data` 地址


这两配置都有 server.port 配置项,用于启动不同端口的服务器。😈 为什么选择 server.port 配置呢?因为 Spring Cloud 项目启动后,从日志中就可以看到生效的服务器端口,嘿嘿~

3.2 简单测试

② 开发环境示例:直接在 IDEA 中,增加 --spring.profiles.active=dev 到 Program arguments 中。如下图所示:IDEA 配置 - dev

使用 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 中。如下图所示:IDEA 配置 - prod

使用 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 的自动刷新配置的功能。最终项目代码如下图所示:

`labx-28-sc-consul-config-auto-refresh` 项目

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 配置项发生变化时,重新设置日志组件的日志级别。如下图所示:LoggingRebinder 源码

下面,我们来实现一个自定义的 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 相关的官方文档:

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值