概述

  • Springcloud config为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供一个中心化的外部配置
  • Springcloud Config分为服务端客户端两部分。
    • 服务端也称分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密、解密信息等访问接口。
    • 客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器
  • 默认采用git来存储配置信息(也有其他方式,比如支持svn和本地文件),但还是推荐git,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

能干嘛

  • 集中管理配置文件
  • 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
  • 运行期间动态调整配置,不再需要在每个服务器的机器上编写配置文件,服务会向配置中心同意拉去配置自己的信息
  • 当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置
  • 将配置信息以REST接口的形式暴露
  • post,curl访问刷新均可

服务端配置

搭建服务中心

  • 使用在GitHub上新建一个名为 scconfig 的新Respository,获得刚新建的git地址

  • 在本地硬盘目录上新建Git仓库并clone,此时在本地D盘下 C:\Users\fsun7\Desktop\scconfig, 文件保存格式必须为UTF-8

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    git clone git@gitee.com:fulsun/scconfig.git
    # springcloud-config新建文件config-dev.yml
    PS C:\Users\fsun7\Desktop\scconfig> cat .\springcloud-config\config-dev.yml
    config:
    info: "master branch, config/config-dev.yml, version = 1"

    # 提交到仓库
    C:\Users\fsun7\Desktop\scconfig>git add .
    C:\Users\fsun7\Desktop\scconfig>git commit -m "add config"
    C:\Users\fsun7\Desktop\scconfig>git push origin master
    Enumerating objects: 5, done.
    Counting objects: 100% (5/5), done.
    Delta compression using up to 8 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (4/4), 482 bytes | 60.00 KiB/s, done.
    Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
    remote: Powered by GITEE.COM [GNK-6.1]
    To gitee.com:fulsun/scconfig.git
    37b8eff..b06272d master -> master
  • 新建配置中心模块 cloud-config-center-3344

  • 依赖配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>
  • YML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    server:
    port: 3344

    eureka:
    client:
    service-url:
    defaultZone: http://127.0.0.1:7001/eureka/
    spring:
    application:
    name: cloud-config-center
    cloud:
    config:
    server:
    git:
    # git仓库地址,私有仓库,需要多配置username和password
    uri: git@gitee.com:fulsun/scconfig.git
    # 搜索目录
    search-paths:
    - springcloud-config

    label: master #读取分支
  • 主启动类

    1
    2
    3
    4
    5
    6
    7
    8
    @SpringBootApplication
    @EnableConfigServer
    @EnableEurekaClient
    public class ConfigCenterMain3344 {
    public static void main(String[] args) {
    SpringApplication.run(ConfigCenterMain3344.class, args);
    }
    }

    测试

    • 启动微服务3344, 测试通过config微服务是否可以从GitHub上获取配置内容

    • 访问 http://localhost:3344/master/config-dev.yml ,成功实现用SpringCloud Config通过GitHub获取配置信息

      ![](13-分布式配置中心SpingCloud config/aeb0be78b372be1f3e48fdc64edb7c8f.png)

配置读取规则

读取不存在的配置

  • 分支label不存在会报错

    ![](13-分布式配置中心SpingCloud config/e287c9497897b2d64d9d6102961262fa.png)

  • 分支存在,配置文件不存在,不报错,内容显示为空

    ![](13-分布式配置中心SpingCloud config/a04fea4f350ab5e103a19d033cc6bfd3.png)

    ![](13-分布式配置中心SpingCloud config/b6ac41f6b58b82f90e4a1ebd4f49be95.png)

bootstrap&application

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

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

加载顺序

  • 若application.yml 和bootstrap.yml 在同一目录下:bootstrap.yml 先加载 application.yml后加载

  • bootstrap.yml 用于应用程序上下文的引导阶段。由父Spring ApplicationContext加载。

配置区别

  • bootstrap.yml 和 application.yml 都可以用来配置参数。

  • bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。一旦bootStrap.yml 被加载,则内容不会被覆盖。

  • application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。

属性覆盖问题

  • 启动上下文时,Spring Cloud会创建一个 Bootstrap Context,作为 Spring 应用的 Application Context 的父上下文。

  • 初始化的时候,Bootstrap Context 负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的 Environment。Bootstrap 属性有高优先级,默认情况下,它们不会被本地配置覆盖

  • 也就是说如果加载的 application.yml 的内容标签与 bootstrap 的标签一致,application 也不会覆盖 bootstrap,而 application.yml 里面的内容可以动态替换。

bootstrap.yml的场景

  • 当使用 Spring Cloud Config Server 配置中心时,这时需要在 bootstrap.yml 配置文件中指定 spring.application.namespring.cloud.config.server.git.uri,添加连接到配置中心的配置属性来加载外部配置中心的配置信息
  • 一些固定的不能被覆盖的属性
  • 一些加密/解密的场景

客户端配置

搭建客户端

  • 新建 cloud-config-center-3355

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <dependencies>
    <!-- config客户端依赖 -->
    <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>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>
  • application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    server:
    port: 3355

    spring:
    application:
    name: config-client

    eureka:
    client:
    service-url:
    defaultZone: http://localhost:7001/eureka
  • bootstrap.yml

    1
    2
    3
    4
    5
    6
    7
    spring:
    cloud:
    config:
    label: master #分支名称
    name: config #配置文件名称
    profile: dev #读取后缀名称 上述三个综合http://localhost:3344/master/config-dev.yml
    uri: http://localhost:3344 #配置中心的地址
  • 主启动类

    1
    2
    3
    4
    5
    6
    7
    @SpringBootApplication
    @EnableEurekaClient
    public class ConfigClientMain3355 {
    public static void main(String[] args) {
    SpringApplication.run(ConfigClientMain3355.class, args);
    }
    }
  • 业务类:显示配置文件的信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @RestController
    public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
    return configInfo;
    }
    }

测试

  • 启动eureka后,启动服务端3344和客户端3355.

  • 访问 http://127.0.0.1:3355/configInfo , 能够正常访问配置文件

    ![](13-分布式配置中心SpingCloud config/0752466dd676323bab457c960d4b12c9.png)

  • 修改config-dev.yml配置并提交到Git仓库b中,比如更新版本号version=2, 再次访问,发现输出的版本还是1的。

  • 重启项目后重新访问才能访问到2版本的配置。问题随时而来,分布式配置的动态刷新问题

客户端动态刷新

  • 通过上面的测试,发现了更新仓库的配置文件后,需要重启服务才能够访问,这种方式在生产环境不可取。

动态刷新

  • 修改3355模块,POM引入actuator监控

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
  • 修改YML,暴露监控接口

    1
    2
    3
    4
    5
    6
    #暴露监控端点
    management:
    endpoints:
    web:
    exposure:
    include: "*"
  • 业务类Controller修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @RestController
    @RefreshScope // 实现刷新功能
    public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo() {
    return configInfo;
    }
    }

测试

  • 重启项目,访问 http://127.0.0.1:3355/configInfo 后,当前为2版本

  • 修改git仓库的版本为3后,再次访问, 结果没有变化,需要运维人员发送Post请求刷新3355

  • 必须是POST请求

    1
    2
    C:\Users\fsun7>curl  -X POST "http://localhost:3355/actuator/refresh"
    ["config.client.version","config.info"]
  • 再次访问 http://127.0.0.1:3355/configInfo ,配置文件更新成功。

webhook

  • 虽然上面能够实现配置的动态刷新,但是修改配置后需要发送post请求,有没有什么办法只要提交代码就自动调用客户端来更新呢?

  • github的webhook是一个好的办法。

  • WebHook是当某个事件发生时,通过发送http post请求的方式来通知信息接收方。Webhook来监测你在Github.com上的各种事件,最常见的莫过于push事件。如果你设置了一个监测push事件的Webhook,那么每当你的这个项目有了任何提交,这个Webhook都会被触发,这时Github就会发送一个HTTP POST请求到你配置好的地址。

  • 如此一来,你就可以通过这种方式去自动完成一些重复性工作,比如,你可以用Webhook来自动触发一些持续集成(CI)工具的运作,比如Travis CI;又或者是通过 Webhook 去部署你的线上服务器。

  • 下图就是gitee上面的webhook配置。

    ![](13-分布式配置中心SpingCloud config/2a502d21b14257f8a88d3c8dc0100a5c.png)

  • 这样我们就可以利用hook的机制去触发客户端的更新,但是当客户端越来越多的时候hook支持的已经不够优雅,另外每次增加客户端都需要改动hook也是不现实的。

  • 其实Spring Cloud给了我们更好解决方案(bus消息总线),提供大范围的自动刷新。