大聪明教你学Spring Cloud核心组件 | 第四篇:配置中心(Config)

·  阅读 7731

前言

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

提到配置文件,大家的脑海里肯定会想到各种各样的配置文件,数据库配置文件、redis配置文件、yml配置文件等等... 尤其是在Spring Boot项目中,除了引入相应的 maven 包之外,更重要的工作就是完善配置文件了,例如 mysql、redis等等的相关的配置。除了项目运行的基础配置之外,还有一些配置是与我们业务有关系的,比如说短信相关、邮件相关,或者一些业务上的开关。 对于一些简单的项目来说,我们一般都是直接把相关配置放在单独的配置文件中,以 properties 或者 yml 的格式出现,更省事儿的方式是直接放到 application.properties 或 application.yml 中。但是这样的方式有个明显的问题,那就是,当修改了配置之后,必须重启服务,否则配置无法生效。 那么这时候就该轮到SpringCloud中的第四个组件——配置中心(Config)闪亮登场了。

什么是配置中心(Config)?

还是先给大家介绍一下什么是配置中心(Config)。

在分布式系统中,由于服务数量巨多,配置文件更是数不胜数,那么为了方便服务配置文件统一管理,就产生了配置中心。

配置中心所包含的核心功能主要有以下几点:

  • 提供服务端和客户端支持
  • 集中管理各环境的配置文件
  • 配置文件修改之后,可以快速的生效
  • 可以进行版本管理
  • 支持大的并发查询
  • 支持各种语言

Spring Cloud Config就可以完美的支持以上所有的需求。Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。

下面直接上代码,以 gitee 作为配置存储为例子,给大家讲解一下Spring Cloud Config的用法。

实现最简单的配置中心

最简单的配置中心,就是启动一个服务作为服务方,之后各个需要获取配置的服务作为客户端来这个服务方获取配置。 首先咱们需要在gitee中新建一个仓库,并上传几个配置文件(不会向gitee上传文件的小伙伴可以百度一下,百度上有很多教程,这里就不多说了)。 在这里插入图片描述

上图是目录结构,里面存储了三个配置文件,配置文件的内容大致相似,如下图所示: 在这里插入图片描述

🥝🥝这里需要注意的是,配置文件名称不能乱起,例如我上传的配置文件的名称是ziye-dev.yml,其中ziye是项目名,而dev代表着开发环境中所使用的开发版配置文件。

接下来咱们新建一个config-server项目(项目的新建方式与上几篇博客中的新建方式相同),跟之前的项目不同的依然是pom.xml文件和yml配置文件。

🍓pom.xml文件 🍓

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springboot</groupId>
    <artifactId>config-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>config-server</name>
    <description>Demo project for springboot config</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR10</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
复制代码

🍓application.yml配置文件🍓

server:
  port: 8012
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/trs_sjz/springcloud-config
          username: xxxx
          password: xxxx
          basedir: D:\springcloudconfig\gitee
          search-paths: config-cloud
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8081/eureka/
复制代码

🥝🥝这里需要注意的是🥝🥝

  1. 如果你的仓库是一个私有仓库,username和password这两个参数就必须要填写,对应着gitee的登录账号和密码;如果是一个共有仓库,则可以不写这两个参数。
  2. basedir代表的含义是:从gitee上把yml配置文件保存到本地的指定目录中
  3. search-paths的含义是:配置文件所在根目录

最后在启动类文件中新增@EnableConfigServer和@EnableEurekaClient注解,配置完成后我们先启动Eureka注册中心项目(第一篇博客中所建的项目,不需要任何修改),再启动config-server项目进行测试。

特别提示: Spring Cloud Config 有它的一套访问规则,我们通过这套规则在浏览器上直接访问就可以。

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
复制代码

{application} 就是应用名称,对应到配置文件上来,就是配置文件的名称部分,例如我上面创建的配置文件。

{profile} 就是配置文件的版本,我们的项目有开发版本、测试环境版本、生产环境版本,对应到配置文件上来就是以 application-{profile}.yml 加以区分,例如application-dev.yml、application-sit.yml、application-prod.yml。

{label} 表示 git 分支,默认是 master 分支,如果项目是以分支做区分也是可以的,那就可以通过不同的 label 来控制访问不同的配置文件了。

因为我上传到gitee的配置文件都是yml格式的,所以只需要对应着前三条规则即可,那么我们可以打开浏览器,访问http://localhost:8012/ziye/dev/master地址。如果浏览器中正常返回了数据,那么就证明了配置中心服务端一切正常。

在这里插入图片描述 在这里插入图片描述

创建配置中心客户端,使用配置

配置中心服务端好了,配置数据准备好了,接下来我们就要在项目中使用它了。我们再新建一个config-client项目(新建方式与config-server相同,pom.xml文件与config-server所引入的maven依赖也是相同的)。

config-client项目中最特别的就是配置文件了,与之前的项目所不同的是,它用到了两个配置文件,分别是bootstrap.yml和application.yml。

🍓bootstrap.yml🍓

spring:
  profiles:
    active: dev
---
spring:
  profiles: prod
  application:
    name: ziye
  cloud:
    config:
      uri: http://localhost:8012
      label: master
      profile: prod
---
spring:
  profiles: dev
  application:
    name: ziye
  cloud:
    config:
      uri: http://localhost:8012
      label: master
      profile: dev

复制代码

在bootstrap.yml配置文件中我们配置了两个版本的配置,并通过 spring.profiles.active 设置当前使用的版本,例如本例中使用的 dev 版本。

🍓application.yml🍓

server:
  port: 3302
management:
  endpoint:
    shutdown:
      enabled: false
  endpoints:
    web:
      exposure:
        include: "*"

data:
  env: NaN
  user:
    username: NaN
    password: NaN
复制代码

其中 management 是关于 actuator 相关的,接下来自动刷新配置的时候需要使用,这里就不多说了。 data 部分是当无法读取配置中心的配置时,使用此配置,以免项目无法启动。

要读取配置中心的内容,需要增加相关的配置类,SpringCloud Config 读取配置中心内容的方式和读取本地配置文件中的配置是一模一样的。可以通过 @Value 或 @ConfigurationProperties 这两种方式来获取。

🍓 @Value方式读取配置文件 🍓

@Data
@Component
public class GitConfig {

    @Value("${data.env}")
    private String env;

    @Value("${data.user.username}")
    private String username;

    @Value("${data.user.password}")
    private String password;

}
复制代码

🍓 @ConfigurationProperties读取配置文件 🍓

@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitAutoRefreshConfig {

    public static class UserInfo {
        private String username;

        private String password;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        @Override
        public String toString() {
            return "UserInfo{" +
                    "username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    '}';
        }
    }

    public String getEnv() {
        return env;
    }

    public void setEnv(String env) {
        this.env = env;
    }

    private String env;

    private UserInfo user;
}
复制代码

接下来再新建一个GitController,来测试使用配置

package com.springboot.configclient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GitController {
    @Autowired
    private GitConfig gitConfig;

    @Autowired
    private GitAutoRefreshConfig gitAutoRefreshConfig;

    @GetMapping(value = "show")
    public Object show(){
        return gitConfig;
    }

    @GetMapping(value = "autoShow")
    public Object autoShow(){
        return gitAutoRefreshConfig;
    }
}

复制代码

最后我们启动项目,在浏览器中分别访问一下http://localhost:3302/show和http://localhost:3302/autoShow,我们可以看到配置信息被成功的获取了。 在这里插入图片描述 在这里插入图片描述

实现自动刷新

SpringCloud Config 在项目启动时加载配置内容这一机制,导致了它存在一个缺陷,就是修改配置文件内容后不会自动刷新。例如我们上面的项目,当服务已经启动的时候,去修改gitee上的配置文件内容,这时候我们再次刷新页面,对不起,页面中展示的还是旧的配置内容,新内容不会主动刷新过来。 如果是这样的话,那还不如不用配置中心,直接用本地配置文件岂不是更快更方便。 为了解决这一问题,它提供了一个刷新机制,但是需要我们主动触发。那就是 @RefreshScope 注解并结合 actuator ,==此时别忘了引入 spring-boot-starter-actuator 包。== 上面贴出来的application.yml配置文件中, management部分就是关于 actuator的,来帮我们实现自动刷新。

接下来我们需要对GitController进行一个小小的改造,对其增加一个@RefreshScope注解(@RefreshScope 注解增加在需要读取配置的类中)

package com.springboot.configclient;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class GitController {
    @Autowired
    private GitConfig gitConfig;

    @Autowired
    private GitAutoRefreshConfig gitAutoRefreshConfig;

    @GetMapping(value = "show")
    public Object show(){
        return gitConfig;
    }

    @GetMapping(value = "autoShow")
    public Object autoShow(){
        return gitAutoRefreshConfig;
    }
}

复制代码

修改完成后,重启一下client端,我们修改gitee上的配置文件内容,并提交更改,再次刷新页面,这时候是没有反应的,我们需要发送 POST 请求到 http://localhost:3302/actuator/refresh 这个接口(用postman之类的工具即可),请求成功后会触发加载新的配置信息。

此时我们在浏览器中再分别访问http://localhost:3302/show和http://localhost:3302/autoShow这两个地址,我们会发现http://localhost:3302/autoShow地址返回的配置信息是最新的,而http://localhost:3302/show返回的配置信息依然是旧的,这与@Value注解的实现有关,所以我们在项目中就不推荐使用@Value的方式去加载配置信息了。

结语

当我们系统业务扩展到一定程度的时候,免不了会增加很多的配置文件和信息,例如证书文件、接口对接的参数信息、数据库连接信息等,传统的单体式架构系统,SSH、SSM还是Struts等,只能是一个文件一个文件的增加堆积到项目系统中。每次更改配置信息的时候,都要重启服务器,影响线上业务浪费时间等。当配置文件数量达到一定程度的时候,整个项目就会看起来非常臃肿冗余,更甚者可能会拿错配置信息导致程序崩溃等。那么,这时候分布式系统采用的配置中心的优势就突出出来了。由业务拆分的多个模块系统的各配置文件,全部配置在配置中心统一管理,大幅度的减轻了开发者在管理配置文件时的工作量,可以帮助开发者更方便更快捷的统一管理这些配置。

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

爱你所爱 行你所行 听从你心 无问东西

分类:
后端
分类:
后端
收藏成功!
已添加到「」, 点击更改