SpringCloud使用Consul作为配置中心

一、前言

什么是配置中心?

微服务意味着要将单体应用中的业务拆分成一个个子服务,这些服务都需要必要配置信息才能运行,每个微服务都包含一个类似application.yml的配置文件,单个管理显得极其麻烦,于是集中式的管理思想诞生了,该思想旨在微服务模块之外提供一个集中化的外部配置支持平台,为每个微服务提供配置支持,这个平台称为配置中心。

Spring Cloud Config配置中心?

Spring Cloud Config就是最早期cloud当中的配置中心,但是需要配合git,svn 或外部存储(例如各种数据库),且需要配合Spring Cloud Bus实现配置刷新。

Consul注册中心

https://blog.csdn.net/weixin_43888891/article/details/125511531这一篇文章我们学习了Spring Cloud Consul作为注册中心的使用方案,且作为Spring Cloud官方推荐替换Eureka 注册中心的方案。

Consul配置中心

Spring Cloud 官方还声明 Consul 可以作为 Spring Cloud Config 配置中心的替代方案。并且不需要额外的git、svn、数据库等配合,且无需配合Bus即可实现配置刷新

Consul 使用Go语言编写,因此具有天然可移植性(支持Linux,Windows和Mac OS);安装包仅包含一个可执行文件,方便部署,与Docker等轻量级容器可无缝配合。

什么是配置刷新?

所谓配置刷新就是consul配置文件一旦修改,我们应用能立马拿到最新的配置!就比如我们程序有时候经常遇到调用第三方程序接口,我们可以将接口地址配置到注册中心,假如哪天第三方域名修改了,我们不需要重启服务,只需要修改配置中心的配置即可,然后程序能立马拿到最新的访问地址。

Consul 官网:https://www.consul.io/
Consul 官网下载地址:https://www.consul.io/downloads

二、初始化配置

使用Consul作为配置中心,第一步我们先创建目录,把配置信息存储至Consul,点击菜单Key/Value 再点击Create 按钮。
在这里插入图片描述
1.创建 config/ 基本目录,可以理解为配置文件所在的最外层文件夹。

在这里插入图片描述

这个是官网提出的:

cloud官网:https://docs.spring.io/spring-cloud-consul/docs/current/reference/html/#spring-cloud-consul-config

在这里插入图片描述
为什么要用config作为根目录?

consul给我们提供的是key/value存储,也就意味着不仅仅可以存储配置文件,还可以进行存储别的东西,所以这里官网也是提出使用config作为根目录。

2.接下来在config下创建以下文件夹,这些文件夹代表的是应用文件夹,而并不是真正的配置文件!

orderService-dev就代表的是orderService服务的dev环境的应用文件夹。官网 提出的config/testApp, dev/服务与环境区分使用逗号分割,读consul的配置的时候默认也是逗号,但是逗号比较丑,我们这里用的-分割,然后我们在读取consul的服务配置文件声明使用-分割即可。

在这里插入图片描述
3.创建配置文件,创建文件的时候不带/就是创建文件

在每个应用文件夹下创建配置文件,这里可以选择格式,我使用的YAML格式,注意这里是有语法校验的,假如有空格什么的都会报错的,建议在ider的yml文件写好配置后再进行复制到里面。

配置文件当中的name没有实质意义,就是为了测试 获取不同环境的配置。所以我们每个配置文件当中的name设置成不一样的。

在这里插入图片描述
假设以上内容为订单微服务的配置信息,下面我们通过案例来加载Consul配置中心中的配置信息。

三、代码练习

本篇文章采用了maven聚合工程,搭建父工程这些我就不记录了,完全是基于https://blog.csdn.net/weixin_43888891/article/details/125267683文章的项目进行开发的,具体参考这一篇文章!

git源码:https://gitee.com/gzl_com/spring-cloud.git

1. 创建cloud-consul-configdemo8007项目

在这里插入图片描述

2. 修改配置

修改pom:

<dependencies>
    <!--spring cloud consul discovery 服务发现依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    </dependency>
    <!--spring cloud consul config 配置中心依赖 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-consul-config</artifactId>
    </dependency>
    <!-- SpringBoot整合Web组件 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 健康检查 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- 使用@ConfigurationProperties注解警告的问题 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <!--日常通用jar包配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

添加 bootstrap.yml

server:
  port: 8007 # 端口

spring:
  application:
    name: config-demo # 应用名称
  profiles:
    active: dev # 指定环境,默认加载default环境
  cloud:
    consul:
      # Consul 服务器地址
      host: localhost
      port: 8500
      # 配置中心相关配置
      config:
        # 是否启用配置中心,默认值 true 开启
        enabled: true
        # 设置配置的基本文件夹,默认值config 可以理解为配置文件所在的最外层文件夹
        prefix: config
        # 设置应用的文件夹名称,默认值application 一般建议设置为微服务应用名称
        default-context: orderService
        # 配置环境分隔符,默认值","和default-context配置项搭配
        # 例如应用orderService 分别有环境 default, dev, test, prod
        # 只需 config 文件下创建 orderService, orderService-dev, orderService-test, orderService-prod文件夹
        profile-separator: '-'
        # 指定配置格式为yamL
        format: yaml
        # Consul Key/Values 中的Key, Value 对应整个配置文件
        data-key: orderServiceConfig
        # 以上配置可以理解为:加载 config/orderService/ 文件夹下Key 为orderServiceConfig 的Value 对应的配置
        watch:
          # 是否开启自动刷新,默认值true 开启
          enabled: true
          # 刷新频率,单位:毫秒,默认值1000
          delay: 1000
      discovery:
        register: true                             # 是否需要注册
        instance-id: ${spring.application.name}-01 # 注册实例id(必须唯一)
        service-name: ${spring.application.name}   # 服务名称
        port: ${server.port}                       # 服务端口(默认就是当前服务端口)
        prefer-ip-address: true                    # 是否使用ip地址注册(开启后可以在web界面看到实例ip)
        ip-address: ${spring.cloud.client.ip-address} # 服务请求ip(默认就是当前服务ip)

3. 添加主启动类

@EnableDiscoveryClient这个注解是服务发现使用的,但是经过试验,当不使用这个注解注册中心照样能注册进去,并且使用RestTemplate通过服务名称调用服务的时候也没有发现什么问题。所以我怀疑只要是加入了consul服务发现的依赖和配置了consul,就自动开启了,有没有这个注解都可以,针对于这个问题,我专门看了一下我们实际开发当中的项目,他启动类也带了这个注解,所以建议还是加上。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ConfigDemoMain8007 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigDemoMain8007.class, args);
    }
}

4. 读取配置文件

一般读取yml当中的配置文件的方式有两种,一种是使用@ConfigurationProperties注解以前缀的形式注入到bean当中,一种是以@Value("${name}")注解的形式注入到属性当中。本篇案例这两种都会练习。

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "mysql")
@Data
public class MysqlProperties {

    private String host;
    private Integer port;
    private String username;
    private String password;
}

5. 添加controller

import com.gzl.cn.config.MysqlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RefreshScope
@RestController
public class ConfigController {
    @Autowired
    private MysqlProperties mysqlProperties;

    @Value("${name}")
    private String name;

    @GetMapping("/name")
    public String getName() {
        return name;
    }

    @GetMapping("/mysql")
    public MysqlProperties getMysqlProperties() {
        return mysqlProperties;
    }
}

最终结构:

在这里插入图片描述

6. 启动测试

观察注册中心的服务,已经成功注册上了!

在这里插入图片描述

访问:http://localhost:8007/mysql

在项目的配置文件当中我们并没有配置mysql相关属性,访问接口的时候读出来的配置就是从consul上读取的配置。

在这里插入图片描述
访问:http://localhost:8007/name

在这里插入图片描述

访问出来的name是:order-service-dev,原因就是我们bootstrap的profiles是设置的dev环境。假如设置test就是读取的test的配置

在这里插入图片描述

假如我们不设置profiles,读取的就是不带环境的应用名称配置:

在这里插入图片描述

7. 动态刷新配置

现在配置文件读取的是dev的,假如修改dev配置环境的配置,过个几秒就会动态刷新配置。所谓动态刷新就是consul配置文件一旦修改,我们应用能立马拿到最新的配置!

在这里插入图片描述

动态刷新的时候控制台会有打印日志的,当日志出来之后我们再去访问获取配置的接口,会发现配置已经是最新的了。

在这里插入图片描述
Consul 使用 Spring 定时任务 Spring TaskScheduler 来监听配置文件的更新。

默认情况下,它是一个定时任务线程池ThreadPoolTaskScheduler ,其poolSize值为1,要更改TaskScheduler,请创建-TaskSchedulerConsulConfigAutoConfiguration. CONFIG_WATCH_TASK_SCHEDULER_NAME 常量命名的bean类型,下图是官网说明:

在这里插入图片描述

如果 consul 不可用于配置,在某些情况下(如本地开发或某些测试场景)可能会很方便。设置spring.cloud.consul.config.fail-fast=false将导致配置模块记录警告而不是抛出异常。这将允许应用程序继续正常启动。

四、application.yml与bootstrap.yml的区别

Spring Boot 默认支持 properties(.properties)YAML(.yml .yaml)两种格式的配置文件,yml和 properties文件都属于配置文件,功能一样。

Spring Cloud 构建于 Spring Boot 之上, 在 Spring Boot 中有两种上下文,一种是bootstrap,另外一种是 application

1. 不使用bootstrap的后果

在springcloud官网,使用consul的案例当中,反复在提示这一句话,那么这到底是为什么呢?
在这里插入图片描述

首先在上面示例当中我使用的是bootstrap.yml,并没有使用application.yml,那么使用application.yml到底会有什么后果?

通过将bootstrap改为application后,项目直接启动报错。

在这里插入图片描述
在上一篇我写的Consul作为注册中心文章当中,并没有用bootstrap,而是用的application,项目照样运行正常,他和本篇项目最大的区别就是使用了consul的key/value配置,那也就意味着,consul配置中心相关的配置,必须要放到bootstrap.yml当中,下面我们会进行证实这个问题。

2. 两个的区别

区别:

  • bootstrap.ymlapplication.yml 都可以用来配置参数。
  • bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
  • application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。如果搭配 config 使用, application.yml里面定义的文件可以实现动态替换

加载顺序:

  • 若application.yml 和bootstrap.yml 在同-目录下: bootstrap.yml 先加载,application.yml后加载
  • bootstrap.yml 用于应用程序上下文的引导阶段。bootstrap.yml 由父Spring ApplicationContext加载。

属性覆盖问题:

  • application.yml 与 bootstrap 存在相同的配置项,还是会覆盖 bootstrap,而 application.yml 里面的内容可以动态替换。

3. 测试application和bootstrap

针对于application和bootstrap两个配置文件的几个场景进行测试:

(1) 测试application和bootstrap属性覆盖的问题

关于覆盖的问题,可以拿上面的案例直接测试,创建application.yml,然后修改端口号为8008,直接启动项目,项目可以启动成功,并且端口是8008,而并没有取bootstrap.yml当中的端口,证明application会覆盖了bootstrap配置的属性

(2) 测试在consul的配置文件当中配置了端口,bootstrap也配置了端口,application并没有配置端口

首先运行过程中修改consul当中的端口是不会影响程序的端口的
启动的时候,consul配置的端口会覆盖bootstrap配置的端口,最终会取consul的端口

(3) 测试在consul的配置文件当中配置了端口,bootstrap也配置了端口,application也配置端口

经过测试,发现也是取的consul的配置的端口

通过以上三次测试可以得出结论:consul配置 > application.yml > bootstrap.yml

4. 使用注意

假如我们用到了consul作为配置中心,最重要的一点就是,需要将consul配置中心的相关配置需要放到bootstrap.yml当中,为什么非得放到bootstrap当中?

以上面案例为准,我们的mysql相关配置并没有在项目配置文件配置,完全是基于consul的配置,那也就意味着必须要让consul优先加载,如果consul配置中心相关配置是在application当中,而不在bootstrap,就会导致在程序当中注入mysql相关配置的时候找不到,因为consul还没加载,所以我们必须要让consul的配置中心相关配置放到bootstrap当中。bootstrap会优先与application加载。

bootstrap.yml:

spring:
  cloud:
    consul:
      # Consul 服务器地址
      host: localhost
      port: 8500
      # 配置中心相关配置
      config:
        # 是否启用配置中心,默认值 true 开启
        enabled: true
        # 设置配置的基本文件夹,默认值config 可以理解为配置文件所在的最外层文件夹
        prefix: config
        # 设置应用的文件夹名称,默认值application 一般建议设置为微服务应用名称
        default-context: orderService
        # 配置环境分隔符,默认值","和default-context配置项搭配
        # 例如应用orderService 分别有环境 default, dev, test, prod
        # 只需 config 文件下创建 orderService, orderService-dev, orderService-test, orderService-prod文件夹
        profile-separator: '-'
        # 指定配置格式为yamL
        format: yaml
        # Consul Key/Values 中的Key, Value 对应整个配置文件
        data-key: orderServiceConfig
        # 以上配置可以理解为:加载 config/orderService/ 文件夹下Key 为orderServiceConfig 的Value 对应的配置
        watch:
          # 是否开启自动刷新,默认值true 开启
          enabled: true
          # 刷新频率,单位:毫秒,默认值1000
          delay: 1000

application.yml:

正常来说除去consul配置中心的相关配置,其余配置是都可以放在consul当中的,就算完全不要application也是可以的。当然profiles.active还是有必要要的,他决定了取consul当中哪个配置文件。

server:
  port: 8009 # 端口

spring:
  application:
    name: config-demo # 应用名称
  profiles:
    active: dev # 指定环境,默认加载default环境
  cloud:
    consul:
      discovery:
        register: true                             # 是否需要注册
        instance-id: ${spring.application.name}-01 # 注册实例id(必须唯一)
        service-name: ${spring.application.name}   # 服务名称
        port: ${server.port}                       # 服务端口(默认就是当前服务端口)
        prefer-ip-address: true                    # 是否使用ip地址注册(开启后可以在web界面看到实例ip)
        ip-address: ${spring.cloud.client.ip-address} # 服务请求ip(默认就是当前服务ip)

5. 区分环境

在实际开发当中我们一般都会分为好几个环境,dev、prod、test,不要配置中心的时候还好区分,但是一旦有了配置中心,就意味着又多了个bootstrap.yml配置文件,那我们应该怎么应对多个环境的配置呢?

这是我们项目的方式:

  • bootstrap-test.properties:就是单纯的放了consul的配置中心相关配置。
  • application-dev.properties:这个就是我们开发时候使用的配置文件,profiles设置为dev,开发的时候根本不使用consul配置中心,consul上的所有配置,在application-dev上都有,这样就是为了避免共用consul配置,老是有人改consul上的配置。
  • application.properties:就是放了一些基本上不会改变的属性。
  • 我们用的是docker和jekins,然后发版的时候直接使用profiles设置为test,然后通过docker run命令,修改consul的地址。也就是bootstrap-test.properties存的地址,实际上就是个测试环境的consul地址。

在这里插入图片描述

五、总结

HashiCorp 公司的Consul可谓是一款全能组件。可用于提供服务发现和服务配置的工具。用go语言开发,具有很好的可移植性,被Spring Cloud纳入其中。

在注册中心方面, Netflix Eureka停止新版本开发, Consul成为了优秀的可替代方案。

在配置中心方面, Consul 亦可替代 Spring Cloud Config作为配置中心使用,且无需配合Git, SVN等工具,无需配合Bus消息总线即可实现集群配置更新。

一旦使用consul的配置中心,那么配置中心相关配置一定要放到bootstrap.yml当中!


版权声明:本文为weixin_43888891原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>