使用 Nacos 的配置功能和自动更新

Nacos 不但可以作为注册中心,同时也可以作为配置中心,方便我们对 SpringCloud 中的各个 SpringBoot 微服务的配置进行统一的管理维护。尤其是当微服务数量较多,并且在不同的服务器上进行部署时,使用配置中心进行统一管理维护的优势就更加明显。

本篇博客仍然使用之前搭建的 Nacos 集群,并在上篇博客 Demo 的基础上进行简单的改造,实现微服务从 Nacos 中读取配置,并且在不重启微服务的前提下,实现微服务代码读取的配置内容,跟随 Nacos 配置的修改而自动更新。本篇博客只介绍关键核心内容,详情请查看源代码,在博客最后会提供源代码下载。


一、微服务的配置文件

首先看一下 Demo 的 SpringCloud 工程结构,如下图所示:

image

工程中有两个微服务 consumer_app 和 provider_app ,使用的服务名称分别为 consumer 和 provider 。

需要注意的是:微服务想要读取 Nacos 中的配置文件,配置文件的名称需要以微服务的名称来命名。因此我们需要在 Nacos 中添加两个配置文件:consumer.yaml 和 provider.yaml 。

当然并非所有的配置内容,都放到 nacos 中进行管理,这个可以根据项目的实际情况而定。以 consumer_app 为例,我们将其配置分别存放在 3 个配置文件中:本地的 application.yml 和 bootstrap.yml ,以及 Nacos 中的 consumer.yaml 。下面先看一下这 3 个配置文件的内容:

本地 bootstrap.yml 的内容如下:(spring 引入了 bootstrap.yaml 文件,会在 application.yml 之前被加载)

#微服务启动后,会优先加载 bootstrap.yml 文件,这里只配置了服务名称,以及nacos连接信息
#本地的 application.yml 也是会加载的,比如服务启动端口就配置在 application.yml 中。
spring:
  application:
    # 微服务的名称,这个很重要,因为需要到 nacos 中获取【微服务名称.yaml】的配置文件
    name: consumer
  cloud:
    nacos:
      # 配置 Nacos 的 ip 和 端口
      server-addr: 192.168.216.129:80
      # 配置登录的 账号 和 密码
      username: nacos
      password: nacos
      config:
        file-extension: yaml

本地 application.yml 的内容如下:

# 本地配置文件,在微服务启动时,也会被加载
server:
  port: 8888

#针对具体的服务,配置使用 nacos 的负载均衡策略(随机策略)
#当前项目中接口提供者的服务名称是 provider
#如果去掉以下的配置,则默认使用 ribbon 的轮训策略
provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

logging:
  level:
    com.jobs: debug

Nacos 中的 consumer.yaml 的配置内容如下:

image


二、读取 Nacos 中的配置以及自动更新

1 父工程和子工程需要引入的依赖

父工程的 pom 文件中需要引入 SpringCloud Alibaba 的依赖:

<!--引入 springCloud alibaba 依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.9.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

需要注意版本之间的兼容性,否则可能会出问题。本篇博客中,使用的版本如下:

  • SpringBoot 的版本为 2.3.12.RELEASE
  • SpringCloud 版本为 Hoxton.SR10
  • SpringCloud Alibaba 的版本为 2.2.9.RELEASE

这里以 consumer_app 子工程为例,需要的依赖如下:

<!--nacos配置管理依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2 使用 @Value 方式读取配置和自动更新

我们以读取 Nacos 中的 consumer.yaml 的 myvalue.dateformat 中的值为例,更改一下 ConsumerController 代码。添加一个新的接口,并在 Controller 上添加 @RefreshScope 注解,核心代码如下所示:

/*
如果使用 $Value 来获取 nacos 中配置文件的配置值,
当 nacos 中配置值修改后,要想让程序中获取的值也立刻更新,
就需要在类上添加 @RefreshScope 注解
*/
@RefreshScope
@RequestMapping("/consumer")
@RestController
public class ConsumerController {

    @Value("${myvalue.dateformat}")
    private String dateformat;

    @GetMapping("/now")
    public String getDateNow() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
    }
}

3 使用 @ConfigurationProperties 的配置类和自动更新

我们以读取 Nacos 中的 consumer.yaml 的 myconfig 下的 name 和 age 的值为例,首先需要添加一个与 Nacos 中配置内容相对应的映射类,具体代码如下所示:

package com.jobs.configpojo;

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

@Data
@Component
@ConfigurationProperties(prefix = "myconfig")
public class MyConfig {
    private String name;
    private Integer age;
}

新创建一个 ConfigTestController 和接口,读取配置的代码如下所示:

package com.jobs.controller;

import com.jobs.configpojo.MyConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/*
如果使用 @ConfigurationProperties 为注解的配置类映射 nacos 配置文件的配置信息,
那么当 nacos 中的配置值修改后,则程序中就能够自动获取到更新,这种方式更加方便
*/
@RequestMapping("/config")
@RestController
public class ConfigTestController {

    @Autowired
    private MyConfig myConfig;

    @GetMapping("/getdata")
    public MyConfig getMyConfig() {
        return myConfig;
    }
}

三、相同配置内容的优先级

在 Nacos 中除了【微服务名称.yaml】配置文件外,也可以添加【微服务名称-profile名称.yaml】配置文件,以 provider_app 为例,我们可以在 Nacos 中添加 2 个配置文件:provider.yaml 和 provider-dev.yaml。

我们可以把一些公用的配置放在【微服务名称.yaml】配置文件中,对于不同环境的中有差异的配置,可以放在【微服务名称-profile名称.yaml】配置文件中,如常用的环境为:开发环境 dev 、测试环境 test 、生成环境 pro 等等,这个名称可以自己随便取。

首先对于 bootstrap.yml 配置文件,由于其加载的时间最早,绝大多数情况下,我们只会将【微服务名称】、【profile 名称】、【Nacos 连接信息】配置在里面,不会配置其它额外的信息,对于 provider_app 微服务来说,其 bootstrap.yml 文件内容如下:

#微服务启动后,会优先加载 bootstrap.yml 文件,这里只配置了服务名称,以及nacos连接信息
#本地的 application.yml 也是会加载的,比如服务启动端口就配置在 application.yml 中。
spring:
  application:
    # 微服务的名称,这个很重要,因为需要到 nacos 中获取【微服务名称.yaml】的配置文件
    name: provider
  profiles:
    #开发环境,比如可以使用 test 表示测试环境,pro 表示生产环境
    active: dev
  cloud:
    nacos:
      # 配置 Nacos 的 ip 和 端口
      server-addr: 192.168.216.129:80
      # 配置登录的 账号 和 密码
      username: nacos
      password: nacos
      config:
        file-extension: yaml

由于在 bootstrap.yml 文件中配置了 spring.profiles.active 为 dev ,因此 provider_app 微服务启动时,会加载这几个配置文件:本地的 application.yml 、Nacos 中的 provider.yaml 和 provider-dev.yaml ,下面列出这 3 个文件的相同名称的配置:

本地 application.yml 的配置内容:

server:
  port: 9091

logging:
  level:
    com.jobs: debug

mytest:
  name: 本地配置值
  depart: 本地部门

Nacos 中添加的 provider.yaml 的配置内容:

image

Nacos 中添加的 provider-dev.yaml 的配置内容:

image

可以看到 3 个配置文件,都有 mytest 下的 name 和 depart 的配置,具体会使用哪个配置内容呢?

在本篇博客的代码中,使用了 @ConfigurationProperties 的配置类的方式读取以上配置,并提供的接口进行验证。首先新增一个与 Nacos 配置映射的配置类,具体细节如下所示:

package com.jobs.configpojo;

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

@Data
@Component
@ConfigurationProperties(prefix = "mytest")
public class MyTest {
    private String name;
    private String depart;
}

然后更改了一下对外提供的接口,代码如下:

package com.jobs.controller;

import com.jobs.configpojo.MyTest;
import com.jobs.pojo.Employee;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.util.Random;

@Slf4j
@RequestMapping("/provider")
@RestController
public class ProviderController {

    @Autowired
    private MyTest myTest;

    @GetMapping("/{id}")
    public Employee getEmployeeById(@PathVariable("id") Integer id) {
        Employee employee = new Employee();
        employee.setId(id);

        //使用配置文件中的配置值
        //配置文件优先级:provider-dev.yaml > provider.yaml > application.yml
        //你可以分别注释 nacos 中 provider-dev.yaml 和 provider.yaml 中的配置,进行验证结果
        employee.setName(myTest.getName());
        employee.setDepart(myTest.getDepart());

        log.info("返回员工的 id 为:" + id);
        return employee;
    }
}

你可以分别 Nacos 中的 provider-dev.yaml 和 provider.yaml 中的配置注释和启用,进行验证,最终的结果为:

【微服务名称-profile名称.yaml】 > 【微服务名称.yaml】 > 【本地 application.yml】

image


本篇博客的源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/nacos_config.zip

posted @ 2023-05-28 12:33  乔京飞  阅读(11915)  评论(0编辑  收藏  举报