《深入理解 Spring Cloud 与微服务构建》第十三章 配置中心 Spring Cloud Config

《深入理解 Spring Cloud 与微服务构建》第十三章 配置中心 Spring Cloud Config

一、Config Server 从本地读取配置文件

Config Server 可以从本地仓库读取配置文件,也可以从远程 Git 仓库读取。本地仓库是指将所有的配置文件统一写在 Config Server 工程目录下。Config Server 暴露 HTTP API 接口,Config Client 通过调用 Config Server 的 HTTP API 接口来读取配置文件

本案例和之前的工程一样,采用多 Module 形式。需要新建一个主 Maven 工程,在 pom 文件中指定 Spring Boot 的版本为 2.1.0,Spring Colud 的版本为 Greenwich.RELEASE

1.构建 Config Server

在主 Maven 工程下,创建一个 Module 工程,工程名取为 config-server,其 pom 文件继承主 Maven 工程的 pom 文件,并在 pom 文件中引入 Config Server 的起步依赖 spring-cloud-config-server。pom 文件代码如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>

在程序的启动类 ConfigServerApplication 加上 @EnableConfigServer 注解,开启 Config Server 的功能,代码如下:

package com.sisyphus;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

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

在工程的配置文件 application.yml 中做相关的配置,包括指定程序名为 config-server,端口号为 8769.通过 spring.profile.active=native 来配置 Config Server 从本地读取配置,读取配置的路径为 classpath 下的 shared 目录。application.yml 的配置文件的代码如下:

server:
  port: 8769

spring:
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/shared
  profiles:
    active: native
  application:
    name: config-server

在工程的 Resources 目录下建一个 shared 文件夹,用于存放本地配置文件。在 shared 目录下,新建一个 config-client-dev.yml 文件,用作 config-client 工程的 dev(开发环境)的配置文件。在 config-client-dev.yml 配置文件中,指定程序的端口号为 8762,并定义一个比哪里 foo,该变量的值为 foo version 1,代码如下:

server:
  port: 8762
foo: foo version 1

2.构建 Config Client

新建一个工程,取名为 config-client,该工程作为 Config Client 从 Config Server 读取配置文件,该工程的 pom 文件继承了主 Maven 工程的 pom 文件, 并在其 pom 文件引入 Conig 的起步依赖 spring-cloud-starter-config 和 WEB 功能的起步依赖 spring-boot-starter-web,代码如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
</dependencies>

在其配置文件 bootstrap.yml 中做程序的配置,注意这里用的是 bootstrap.yml,而不是 application.yml,bootstrap 相对于 application 具有优先的执行顺序。在 bootstrap.yml 配置文件中指定了程序名为 config-client,向 Url 地址为 http://localhost:8769 的 Config Server 读取配置文件。如果没有读取成功,则执行快速失败(fail-fast),读取的是 dev 文件。bootstrap.yml 配置文件中的变量 {spring.application.name} 和变量 {spring.profiles.active},两者以 “-” 相连,构成了向 Config Server 读取的配置文件名,所以本案例在配置中心读取的配置文件名为 cofig-client-dev.yml 文件。配置文件 bootstrap.yml 的代码如下:

spring:
  application:
    name: config-client
  cloud:
    config:
      uri: http://localhost:8769
      fail-fast: true
  profiles:
    active: dev

config-server 工程启动成功后,启动 config-client 工程,你会在控制台的日志中发现 config-client 向 Url 地址为 http://localhost:8769 的 Config Server 读取了配置文件。最终程序启动的端口为 8762,这个端口是在 config-server 的 Resources/shared 目录中的 config-client-dev.yml 的配置文件中配置的,可见 config-client 成功地向 config-server 读取了配置文件

为了进一步验证,在 config-client 工程写一个 API 接口,读取配置文件的 foo 变量,并通过 API 接口返回,代码如下:

package com.sisyphus;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

    @Value("${foo}")
    String foo;

    @RequestMapping("/foo")
    public String hi(){
        return foo;
    }
}

打开浏览器,访问 http://localhost:8762/foo,浏览器显示:

foo version 1

可见 config-client 工程成功地向 config-server 工程读取了配置文件中的 foo 变量的值

二、Config Server 从远程 Git 仓库读取配置文件

Spring Cloud Config 支持从远程 Git 仓库读取配置文件,即 Config Server 可以不从本地的仓库读取,而是从远程 Git 仓库读取。这样做的好处是将配置哦统一管理,并且可以通过 Spring Cloud Bus 在不人工启动程序的情况下对 Config Client 的配置进行刷新。本例采用 Gitee 作为远程 Git 仓库

首先,修改 Config Server 的配置文件 application.yml,代码如下:

server:
  port: 8769

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/jiang-qi-313YPHU3/spring-cloud-config
          searchPaths: respo
          username: 
          password: 
      label: master
  application:
    name: config-server

其中,uri 为远程 Git 仓库的地址,searchPaths 为搜索远程仓库的文件夹地址,username 和 password 为 Git 仓库的登录名和密码。如果是私人 Git 仓库,登录名和密码是必需的;如果是公开的 Git 仓库,可以不需要。label 为 git 仓库的分支名,本例从 master 读取

将上一节的 config-client-dev.yml 上传到远程仓库中,上传的路径为 https://gitee.com/jiang-qi-313YPHU3/spring-cloud-config,读者可以创建自己的仓库进行上传

重新启动 config-server,config-server 启动成功后,启动 config-client,可以发现 config-client 的端口为 8762.像上一节一样,访问 http://localhost:8762/foo,浏览器显示:

在这里插入图片描述

可见,config-server 从远程 Git 仓库读取了配置文件,config-client 从 config-server 读取了配置文件

三、构建高可用的 Config Server

当服务实例很多时,所有的服务实例需要同时从配置中心 Config Server 读取配置文件,这时可以考虑将配置中心 Config Server 做成一个微服务,并且将其集群化,从而达到高可用。Config Server 和 Config Clinet 向 Eureka Server 注册,并且将 Config Server 多实例集群部署

1.构建 Eureka Server

新建一个 eureka-server 工程,eureka-server 工程的 pom 文件继承了主 Maven 的 pom 文件, eureka-server 工程的 pom 文件引入 Eureka Server 的起步依赖 spring-cloud-starter-netflix-eureka-server 和 WEB 功能的起步依赖 spring-boot-starter-web,配置代码如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

在工程的配置文件 application.yml 中做程序的相关配置,指定程序的端口号为 8761,代码如下:

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://localhost:${server.port}/eureka/

在程序的启动类 EurekaServerApplication 上加 @EnableEurekaServer 注解,开启 Eureka Server 的功能,代码如下:

package com.sisyphus;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

2.改造 Config Server

Config Server 作为 Eureka Client,需要在工程中的 pom 文件引入 spring-cloud-starter-netflix-eureka-client 起步依赖,代码如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

在工程的启动类 ConfigServerApplication 加上 @EnableEurekaClient 注解,开启 EurekaClient 的功能

在工程的配置文件 application.yml 文件中制定服务注册的地址,代码如下:

eureka:
  client:
    serviceUrl:
      defaultZone: http://locallhost:8761/eureka/

3.改造 Config Client

和 Config Server 一样作为 Eureka Client,在 pom 文件加上 spring-cloud-starter-netflix-eureka-client
起步依赖,在工程的启动类加上 @EnableEurekaClient 注解,开启 EurekaClient 的功能

在工程的配置文件 application.yml 加上相关配置,指定服务注册中心的地址为 http://localhost:8761/eureka/,向 Service Id 为 config-server 的配置服务读取配置文件,代码如下:

server:
  port: 8762

spring:
  application:
    name: config-client
  cloud:
    config:
      fail-fast: true
      discovery:
        enabled: true
        service-id: config-server
  profiles:
    active: dev

eureka:
  client:
    serviceurl:
      defaultZone: http://localhost:8761/eureka/

依次启动 eureka-server、config-server 和 config-client 工程,注意这里需要 config-server 启动成功并且向 eureka-server 注册完成后,才能启动 config-client,否则 config-client 找不到 config-server

通过控制台可以发现,config-client 向地址为 http://localhost:8769 的 config-server 读取了配置文件。访问 http://localhost:8762/foo,浏览器显示:

foo version 2

可见,config-server 从远程 Git 仓库读取了配置文件,config-client 从 config-server 读取了配置文件

那么如何搭建高可用的 Config Server 呢?只需要将 Config Server 多实例部署,用 IDEA 开启多个 Config Server 实例,端口分别为 8769 和 8768。在浏览器上访问 Eureka Server 的主页 http://localhost:8761/,界面如图所示:

在这里插入图片描述

多次启动 config-client 工程,从控制台可以发现它会轮流地从 http://localhost:8768 和 http://localhost:8769 的 Config Server 读取配置文件,并做了负载均衡

四、使用 Spring Cloud Bus 刷新配置

Spring Cloud Bus 是用轻量的消息代理将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。一个关键的思想就是,消息总线可以为微服务做监控,也可以实现应用程序之间相互通信。Spring Cloud Bus 可选的消息代理组件包括 RabbitMQ、AMQP 和 Kafka 等。本节讲述的是用 RabbitMQ 作为 Spring Cloud 的消息组件去刷新更改微服务的配置文件

为什么需要用 Spring Cloud Bus 去刷新配置?

如果有几十个微服务,而每一个服务又是多实例,当更改配置时,需要重新启动多个微服务实例,会非常麻烦。Spring Cloud Bus 的一个功能就是让这个过程变得简单,当远程 Git 仓库的配置更改后,只需要向某一个微服务实例发送一个 Post 请求,通过消息组件通知其它微服务实例重新拉取配置文件。当远程 Git 仓库的配置更改后,通过发送 “/bus/refresh” Post 请求给某一个微服务实例,通过消息组件,通知其它微服务实例,更新配置文件

本节是在上一节的例子基础上进行改造的,首先,需要在 config-server 和 config-client 的 pom 文件中引入用 RabbitMQ 实现的 Spring Cloud Bus 的起步依赖 spring-cloud-starter-bus-amqp。如果读者需要自己实践,则需要安装 RabbitMQ 服务器。pom 文件添加的依赖如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

在 config-server 和 config-client 工程的配置文件 application.yml 添加 RabbitMQ 的相关配置,host 为 RabbitMQ 服务器的 IP 地址,port 为 RabbitMQ 服务器的端口,username 和 password 为 RabbitMQ 服务器的用户名和密码:

spring:
  rabbitmq:
    host: localhost
    port: 15672
    username: guest
    password: guest
    
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh

最后,需要 config-client 在启动类上加 @RefreshScope 注解,只有加上了该注解,才会在不重启服务的情况下更新配置,如本例中更新配置文件 foo 变量的值,代码如下:

package com.sisyphus;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@EnableEurekaClient
@RefreshScope
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }

    @Value("${foo}")
    String foo;

    @RequestMapping("/foo")
    public String hi(){
        return foo;
    }
}

依次启动工程,其中 config-client 开启两个实例,端口分别为 8762 和 8763.启动完成后,在浏览器上访问 http://localhost:8762/foo 或者 http://localhost:8763/foo,浏览器显示:

foo version 2

更改远程 Git 仓库,将 foo 的值改为 “foo version 3”。通过 Postman 或者其他工具发送一个 Post 请求 http://localhost:8769/actuator/bus-refresh,请求发送成功,再访问 http://localhost:8762/foo 或者 http://localhost:8763/foo,浏览器会显示:

foo version 3

可见,通过向 8762 端口的微服务实例发送 Post 请求 http://localhost:8762/actuator/bus-refresh,请求刷新配置,由于使用了 Spring Cloud Bus,其他服务实例会接收到刷新配置的消息,也会刷新配置。另外,“/actuator/bus-refresh” API 接口可以指定服务,即使用 “destination” 参数,例如 “/actuator/bus-refresh?destination=eureka-client:**”,即刷新服务名为 eureka-client 的所有服务实例

五、将配置存储在 MySQL 数据库中

在大多数情况下,我们将配置存储在 Git 仓库中,即可满足业务需求。Spring Cloud Config 没有页面展示的功能,当我们需要二次开发对配置进行展示和做管控功能时,将配置存储在关系型数据库 MySQL 中可能会更便捷

本节的案例分为 config-server 和 config-client 两部分。其中,config-server 工程需要连接 MySQL 数据库,读取配置;config-client 则是在启动时从 config-server 工程读取。工程的创建过程参考本章第一节

1.改造 config-server 工程

在 config-server 工程的 pom 文件下引入 config-server 的起步依赖、mysql 的连接器、jdbc 的起步依赖,代码如下:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

在 config-server 工程的配置文件 application.yml 下做以下配置:

server:
  port: 8769

spring:
  profiles:
    active: native
  application:
    name: config-server
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/config-server ?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=GMT&2B8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    config:
      label: master
      server:
        jdbc:
          sql: SELECT key1, value1 from config_properties where APPLICATION=? and PROFILE=? and LABEL=?

其中,spring.profiles.active 为 spring 读取的配置文件名,从数据库中读取,必须为 jdbc。spring.datasource 配置了数据库相关的信息,spring.cloud.config.label 读取配置的分支,这需要在数据库中与数据对应,本案例中为 master。spring.cloud.config.server.jdbc.sql 为查询数据库的 sql 语句,该语句的查询字段必须与数据库的表字段一致

2.初始化数据库

由于 config-server 使用的是数据库存储配置,因此读者需要先安装 MySQL 数据库。安装成功后,创建数据库名为 config-server 的数据库,数据库编码为 utf-8,然后在 config-server 数据库下执行以下数据库脚本:

CREATE TABLE `config_properties` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `key1` varchar(50) COLLATE utf8_bin NOT NULL,
  `value1` varchar(500) COLLATE utf8_bin DEFAULT NULL,
  `application` varchar(50) COLLATE utf8_bin NOT NULL,
  `profile` varchar(50) COLLATE utf8_bin NOT NULL,
  `label` varchar(50) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

其中,key1 字段为配置的 key1,value1 字段为配置的值,application 字段对应于应用名,profile 对应于环境,label 对应于读取的分支,一般为 master

插入数据 config-client 的 2 条数据包括 server.port 和 foo 两个配置,具体数据库脚本如下:

insert into `config_properties` (`id`, `key1`, `value1`, `application`, `profile`, `label`) values('1','server.port','8083','config-client','dev','master');
insert into `config_properties` (`id`, `key1`, `value1`, `application`, `profile`, `label`) values('2','foo','bar-jdbc','config-client','dev','master');

依次启动 config-server 和 config-client 两个工程,其中 config-client 的启动端口为 8083,这是在数据库中配置的,可见 config-client 从 config-server 中读取了配置。在浏览器上访问 http://localhost:8083/foo,浏览器显示 bar-jdbc,由此可见 config-client 从 config-server 中成功读取了配置,而配置是存储在数据库中的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值