环境:Nacos 1.4.2

什么是Nacos

一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

通俗解释就是:Nacos是一个注册中心&配置中心

关于Nacos注册中心的功能,在Nacos注册中心实战篇中,阿鉴已经给大家详细介绍了,今天我们就来看看配置中心如何使用吧~

基本使用

在介绍Nacos注册中心实战时,阿鉴已经介绍并搭建好了Nacos集群,这里就直接使用当时的Nacos集群了。

  1. 引入依赖

    my-goods项目引入config依赖

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    
  2. 编辑配置

    spring:
    	application:
        name: my-goods
      cloud:
        nacos:
          config:
            server-addr: 192.168.2.11:8850
            username: nacos
            password: nacos
    
  3. 在nacos新建配置文件并编写配置

    由于我们的配置中并未指定命名空间,所以默认使用public命名空间

    Data ID: 在什么都没有配置的情况下,Data ID为「服务名」或者「服务名.文件扩展名」,也就是my-goods或者my-goods.properties(我们也没有配置文件扩展名,默认为properties)

    Group: 默认为DEFAULT_GROUP

    配置格式:即为文件格式,默认为properties

    配置内容:文件格式是properties, 配置内容即为properties格式写法

  4. 编写代码

    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Value("${goods}")
        public String goods;
    
        @GetMapping("/config")
        public String config(){
            return "this goods is " + goods;
        }
    }
    
  5. 启动服务测试

    此时已经读取到远程的配置

动态配置

Nacos作为配置中心,将配置放在远端管理只是基础能力,更重要的是还提供了方便快捷的动态刷新配置功能。

  1. 修改代码

    要想使得配置具有自动刷新的能力,只需要在对应的类加上@RefreshScope注解即可

    @RefreshScope
    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Value("${goods}")
        public String goods;
    
        @GetMapping("/config")
        public String config(){
            return "this goods is " + goods;
        }
    }
    
  2. 修改Nacos上的配置

    修改配置:apple -> banana

    发布完之后可以看到控制台中出现监听到配置变更的输出

    2021-05-09 22:45:13.103  INFO 5930 --- [168.1.11_8850] c.a.n.client.config.impl.ClientWorker    : [fixed-114.116.212.76_8850] [polling-resp] config changed. dataId=my-goods, group=DEFAULT_GROUP
    2021-05-09 22:45:13.104  INFO 5930 --- [168.1.11_8850] c.a.n.client.config.impl.ClientWorker    : get changedGroupKeys:[my-goods+DEFAULT_GROUP]
    
  3. 再次调用接口

    可以看到配置已经发生了变更

进阶使用

增加服务环境

一般来说,在我们开发项目时,都会区分环境,比如开发环境、测试环境、生产环境,每个环境配置都会有些许不同,比如mysql配置。那我们就会在配置文件中增加以下配置:

spring:
  profiles:
    active: dev

此时Nacos将增加新的Data ID: 服务名-环境名.文件扩展名

即为 my-goods-dev.properties

  1. 修改代码

    @RefreshScope
    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Value("${goods}")
        public String goods;
    
        @Value("${price}")
        public String price;
    
        @GetMapping("/config")
        public String config(){
            return "this goods is " + goods + ", and price is " + price;
        }
    }
    
  2. 新增配置

    增加一个新的data id 为my-goods-dev.properties配置

  3. 重启项目测试

优先级问题

如果在my-goods-dev.properties配置中增加goods=lemon的配置,那么此时my-goods的和my-goods-dev.propertiesgoods配置哪个会生效呢?

  1. my-goods-dev.properties中增加goods=lemon的配置

  2. 直接测试,此时无须重启项目

    从测试结果看出,Nacos的优先级和Spring的优先级相同,带环境名的配置优先

共享配置

虽然本篇一直只用my-goods这一个服务做案例,但是大家不要忘了,我们这其实是一个微服务系统,在一个微服务系统里,总有些配置是会被许多服务共同使用的,比如Redis的配置。

如果每个服务都在自己的配置里单独维护同样的Redis配置,当Redis配置发生变更时,那么每个服务都要改一次,想想其实也是挺恶心的。

为了解决这个问题,Nacos同样贴心的给我们提供了另一种配置方式:共享配置

  1. 编辑配置文件

    增加shared-configs,并将data-id设置为redis.yaml(可定义, 但必须要有文件扩展名)

    spring:
      application:
        name: my-goods
      profiles:
        active: dev
      cloud:
        nacos:
          config:
            server-addr: 114.116.212.76:8850
            username: nacos
            password: nacos
            shared-configs:
              - data-id: redis.yaml
                refresh: true
    

    refresh: true表示动态刷新配置

    此时文件扩展名即为data-id的后缀名

  2. 在nacos中增加配置

    调皮的小伙伴可以试试这里「配置格式」配成Properties会发生什么

  3. 编写代码

    @RefreshScope
    @RestController
    @RequestMapping("/goods")
    @RequiredArgsConstructor
    public class GoodsController {
    
        @Value("${redis}")
        public String redis;
    
        @GetMapping("/redis")
        public String redis(){
            return "redis url is " + redis;
        }
    }
    

    细心的小伙伴可能会说:哎呀呀,你这啥redis配置呀,假的吧!对,大家就假装认为我写了个redis配置就好啦~

  4. 重启项目测试

扩展配置

扩展配置和共享配置的使用方式相同,增加extension-configs即可

spring:
	cloud:
    nacos:
      config:
        server-addr: 114.116.212.76:8850
        username: nacos
        password: nacos
        shared-configs:
          - data-id: redis.yaml
            refresh: true    
        extension-configs:
          - data-id: extension.yaml
            refresh: true 

扩展配置的优先级比共享配置优先级高一些

命名空间

Nacos中还有一个命名空间的概念,不同命名空间的配置相互隔离,相信大家也发现了,在测试案例中,我们一直使用的是一个public的命名空间,这是Nacos的默认命名空间。

通常我们会以项目名做命名空间进行区分,来试试吧~

  1. 假设我们现在做一个商城项目,新建命名空间mall

  2. public命名空间的配置克隆到mall

  3. 修改配置

    spring:
      application:
        name: my-goods
      profiles:
        active: dev
      cloud:
        nacos:
          config:
            server-addr: 114.116.212.76:8850
            username: nacos
            password: nacos
            namespace: mall
            shared-configs:
              - data-id: redis.yaml
                refresh: true
            extension-configs:
              - data-id: extension.yaml
                refresh: true
    

    此时就只会读取mall命名空间下的配置啦

文件扩展名与配置文件名

讲到现在,我们用的文件扩展名和配置文件名(data id)依旧是默认的properties服务名,如果小伙伴想要修改的话可以修改file-extensionprefix

file-extension: 文件扩展名

prefix: data-id的前缀,默认为服务名

优雅使用

我们现在已经学会了如何使用@Value加@RefreshScope实现动态刷新配置,但是不得不说这种方式并不优雅。

可以设想一下,凡是在@Value的地方都要加一个@RefreshScope注解,而且平常一个配置可能在多个地方使用,最后就会变成到处都是@RefreshScope, 要多难看就难看。

当然,Nacos也提供了一个@NacosValue加@NacosConfigurationProperties方式让我们可以不需要再使用@RefreshScope注解,但阿鉴觉得这种方式对系统侵入性太强了。

所以,阿鉴推荐使用@ConfigurationProperties方式管理配置进行使用。

  1. 新建配置类, 在配置类上加上@RefreshScope注解

    @Data
    @RefreshScope
    @ConfigurationProperties(prefix = "fruit")
    public class GoodsProperties {
    
        private String name;
        private double price;
        private int number;
    
    }
    
  2. 使用

    @RestController
    @RequestMapping("/goods")
    public class GoodsController {
    
        @Autowired
        private GoodsProperties goodsProperties;
    
        @GetMapping("/all")
        public String all(){
            String result = "name: %s, price: %s, number: %s";
            return String.format(result, goodsProperties.getName(),
                    goodsProperties.getPrice(), goodsProperties.getNumber());
        }
    }
    

    此时GoodsController可以不再加@RefreshScope注解了

优先级全测试

到现在,我们已经认识了许多的配置格式了,先来总结一下有哪些吧

  • 服务名
  • 服务名.文件扩展名
  • 服务名-环境.文件扩展名
  • 扩展配置
  • 共享配置

那么,它们的优先级是如何的呢?

这里,为了方便展示效果,阿鉴先告诉大家优先级是怎样的:

共享配置 < 扩展配置 < 服务名 < 服务名.文件扩展名 < 服务名-环境.文件扩展名

  1. 修改配置

    spring:
      application:
        name: my-goods
      profiles:
        active: dev
      cloud:
          config:
            server-addr: 114.116.212.76:8850
            username: nacos
            password: nacos
            namespace: mall
            shared-configs:
              - data-id: redis.yaml
                refresh: true
              - data-id: share.properties
                refresh: true
            extension-configs:
              - data-id: extension.properties
                refresh: true
    
  2. 编写代码

    @RefreshScope
    @RestController
    @RequestMapping("/goods")
    @RequiredArgsConstructor
    public class GoodsController {
        /**
         * 测试配置优先级
         */
        @Value("${filename}")
        public String filename;
    
        @GetMapping("/filename")
        public String filename(){
            return "now filename is " + filename;
        }
    }
    
  3. 在Nacos中建出以下配置文件

    nacos中不允许文件为空,所以随便在里面写点什么就行

  4. 先在共享配置share.properties文件中增加配置filename=share.properties

  5. 开始测试

    紧接在,分别依次在

    extension.properties文件中增加filename=extension.properties配置,

    my-goods文件中增加filename=my-goods配置,

    my-goods.properties文件中增加filename=my-goods.properties配置,

    my-goods-dev.properties文件中增加filename=my-goods-dev配置

    效果图如下:

小结

今天阿鉴给大家介绍了Nacos配置中心的功能,关于Nacos的动态配置刷新,多种配置方式,以及如何优雅的使用它,最后还给大家测试了所有配置的优先级:共享配置 < 扩展配置 < 服务名 < 服务名.文件扩展名 < 服务名-环境.文件扩展名。希望小伙伴们有所收获。

那么,Nacos的基本功能到这里就介绍完啦,我们下篇再见~