SpringCloudAlibaba 服务注册发现与注册中心Nacos SpringCloud2020版本

SpringCloud 专栏收录该内容
13 篇文章 0 订阅

本文主要对SpringCloudAlibaba组件Nacos实现服务注册发现和作为配置中心使用进行简单总结,其中SpringBoot使用的2.4.5版本,SpringCloud使用的2020.0.2版本,SpringCloudAlibaba使用的2021.1版本。

一、SpringCloudAlibaba与Nacos简介

1.SpringCloudAlibaba简介

Spring Cloud Alibaba为分布式应用开发提供了一个一站式解决方案。它包含了开发分布式应用服务的必需组件,使开发者能轻松使用Spring Cloud进行分布式应用服务开发。通过Spring Cloud Alibaba,只需添加一些注解和少量配置,就可以将Spring Cloud应用接入阿里分布式应用解决方案,并通过阿里中间件来迅速搭建分布式应用系统。

Spring Cloud Alibaba常用组件:

  • Sentinel:服务限流与降级熔断。
  • Nacos:服务注册发现与配置中心。
  • RocketMQ:分布式消息系统。
  • Seata:分布式事务解决方案。
  • Dubbo:高性能RPC框架。
  • Alibaba Cloud OSS:阿里云对象存储服务。
  • Alibaba Cloud SchedulerX:分布式任务调度。
  • Alibaba Cloud SMS:覆盖全球的短信服务。

2.Nacos简介

Nacos致力于发现、配置和管理微服务。Nacos提供了一组简单易用的特性集,用于快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos使地构建、交付和管理微服务平台变得更容易。 Nacos是构建以“服务”为中心的现代应用架构的服务基础设施。

Nacos关键特性:

  • 服务发现和服务健康监测:Nacos支持基于DNS和基于RPC的服务发现。Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务。Nacos提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。
  • 动态配置服务:动态配置服务可以以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置,配置变更时无需重新部署应用和服务。配置中心化管理能更加简单地实现无状态服务,使服务按需弹性扩展变得更容易。
  • 动态DNS服务:动态DNS服务支持权重路由,更容易实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能更容易地实现以DNS协议为基础的服务发现。
  • 服务及其元数据管理:Nacos能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的SLA以及最首要的metrics统计数据。

二、安装并运行Nacos

1.预备环境准备

Nacos依赖Java环境来运行。如果是从代码开始构建并运行Nacos,还需要为此配置Maven环境,请确保是在以下版本环境中安装使用:

  1. 64 bit OS,支持Linux/Unix/Mac/Windows,推荐选用Linux/Unix/Mac。
  2. 64 bit JDK 1.8+;下载&配置
  3. Maven 3.2.x+;下载&配置

2.下载源码或安装包

从Github上下载源码方式:

git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

最新稳定版本下载编译后压缩包nacos-server-$version.zip的方式:

unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin

3.启动服务器

Linux/Unix/Mac启动命令(standalone代表着单机模式运行,非集群模式):

sh startup.sh -m standalone

如果使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:

bash startup.sh -m standalone

Windows启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

Nacos下载的2.0.1版本,在Windows运行成功后,可以访问http://localhost:8848/nacos查看Nacos的管理页面,默认账号密码都是nacos:
1

4.关闭服务器

Linux/Unix/Mac关闭命令:

sh shutdown.sh

Windows关闭命令:

shutdown.cmd

或者双击shutdown.cmd运行文件。

三、Nacos实现服务注册与发现

通过Maven新建一个名为spring-cloud-alibaba-nacos-discovery-provider的项目作为服务提供者(服务生产者),一个名为spring-cloud-alibaba-nacos-discovery-consumer的项目作为服务消费者。

1.服务提供者

编写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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rtxtitanv</groupId>
    <artifactId>spring-cloud-alibaba-nacos-discovery-provider</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>spring-cloud-alibaba-nacos-discovery-provider</name>
    <description>nacos discovery provider</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-boot.version>2.4.5</spring-boot.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloudAlibaba 依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Cloud Alibaba Nacos Discovery 服务发现起步依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

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

Nacos Discovery Starter可以将服务自动注册到Nacos服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery Starter也将服务实例自身的一些元数据信息-例如host,port,健康检查URL,主页等-注册到Nacos。

主启动类:

package com.rtxtitanv;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.NacosDiscoveryProviderApplication
 * @description 主启动类
 * @date 2021/4/30 17:57
 */
@SpringBootApplication
@EnableDiscoveryClient
public class NacosDiscoveryProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoveryProviderApplication.class, args);
    }
}

@EnableDiscoveryClient:开启SpringCloud服务注册于发现

编写配置文件,在application.yml中进行如下配置:

server:
  port: ${PORT:8090}

spring:
  application:
    name: nacos-discovery-provider
  cloud:
    nacos:
      discovery:
        # nacos服务器地址
        server-addr: 127.0.0.1:8848

如果不想使用Nacos实现服务注册与发现,可以将spring.cloud.nacos.discovery.enabled设置为false

创建测试用的Controller:

package com.rtxtitanv.controller;

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

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.controller.ProviderController
 * @description ProviderController
 * @date 2021/4/30 18:01
 */
@RestController
public class ProviderController {

    @Value("${server.port}")
    private String port;
    @Value("${spring.cloud.client.ip-address}")
    private String ip;

    @GetMapping("/home")
    public String home() {
        return "ip:" + ip + ",port:" + port;
    }
}

2.服务消费者

编写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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rtxtitanv</groupId>
    <artifactId>spring-cloud-alibaba-nacos-discovery-consumer</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <name>spring-cloud-alibaba-nacos-discovery-consumer</name>
    <description>nacos discovery consumer</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-boot.version>2.4.5</spring-boot.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloudAlibaba 依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Cloud Alibaba Nacos Discovery 服务发现起步依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- Spring Cloud Loadbalancer 负载均衡起步依赖 Ribbon在SpringCloud 2020版已经移除
        需引入Spring Cloud Loadbalancer -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

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

注意:由于SpringCloud 2020版本已经移除了Ribbon,需要引入spring-cloud-starter-loadbalancer依赖来代替Ribbon实现负载均衡。

主启动类:

package com.rtxtitanv;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.NacosDiscoveryConsumerApplication
 * @description 主启动类
 * @date 2021/4/30 17:57
 */
@SpringBootApplication
@EnableDiscoveryClient
public class NacosDiscoveryConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosDiscoveryConsumerApplication.class, args);
    }
}

编写配置文件,在application.yml中进行如下配置:

server:
  port: ${PORT:8080}

spring:
  application:
    name: nacos-discovery-consumer
  cloud:
    nacos:
      discovery:
        # nacos服务器地址
        server-addr: 127.0.0.1:8848

创建RestTemplate的Bean:

package com.rtxtitanv.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.config.RestTemplateConfig
 * @description RestTemplate配置类
 * @date 2021/5/1 16:36
 */
@Configuration
public class RestTemplateConfig {

    @Bean(name = "restTemplate")
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

Controller层:

package com.rtxtitanv.controller;

import com.rtxtitanv.service.ConsumerService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.controller.ConsumerController
 * @description ConsumerController
 * @date 2021/4/30 18:02
 */
@RestController
public class ConsumerController {

    @Resource
    private ConsumerService consumerService;

    @GetMapping("/test")
    public String consumerTest() {
        return consumerService.consumerTest();
    }
}

Service层:

package com.rtxtitanv.service;

import reactor.core.publisher.Mono;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.service.ConsumerService
 * @description ConsumerService
 * @date 2021/5/1 16:34
 */
public interface ConsumerService {
    /**
     * 使用RestTemplate进行服务调用测试,使用LoadBalancerClient接口获取服务信息
     * 
     * @return 调用nacos-discovery-provider返回的结果
     */
    String consumerTest();
}
package com.rtxtitanv.service.impl;

import com.rtxtitanv.service.ConsumerService;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.service.impl.ConsumerServiceImpl
 * @description ConsumerService实现类
 * @date 2021/5/1 16:42
 */
@Service
public class ConsumerServiceImpl implements ConsumerService {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancerClient loadBalancerClient;

    @Override
    public String consumerTest() {
        ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-discovery-provider");
        String url = serviceInstance.getUri() + "/home";
        return restTemplate.getForObject(url, String.class);
    }
}

3.RestTemplate服务调用

如下图所示方式启动三个服务提供者实例,端口分别为8091、8092、8093:
2
然后启动一个服务消费者实例,查看Nacos的管理页面中的服务列表,可见两个服务都已注册成功:
3
点击详情汉能查看每个服务具体的实例信息:
4
然后不断访问http://localhost:8080/test
5
根据以上结果,可见每次请求访问的实例不同,可见实现了负载均衡。在通过LoadBalancerClient接口在获取服务实例的时,已经实现了对服务提供者实例的负载均衡,默认使用轮询策略。由于SpringCloud 2020版本已经移除了Ribbon,所以在服务消费者中引入spring-cloud-starter-loadbalancer依赖来代替Ribbon实现负载均衡。如果去掉spring-cloud-starter-loadbalancer依赖,则服务消费者在启动时会报如下错误:
6
以上通过LoadBalancerClient接口获取服务实例后拼接url的方式还可以进一步简化,通过@LoadBalanced注解。在创建RestTemplate类型的Bean的方法上需加上@LoadBalanced注解:

@LoadBalanced
@Bean(name = "restTemplate")
public RestTemplate restTemplate() {
    return new RestTemplate();
}

ConsumerController中新增以下方法:

@GetMapping("/test1")
public String consumerTest1() {
    return consumerService.consumerTest1();
}

ConsumerService中新增以下方法:

String consumerTest1();

ConsumerServiceImpl中实现该方法:

@Override
public String consumerTest1() {
    return restTemplate.getForObject("http://nacos-discovery-provider/home", String.class);
}

重新启动服务消费者后不断访问http://localhost:8080/test1
7
如果去掉服务消费者中的 spring-cloud-starter-loadbalancer依赖,则在服务调用的时候会报如下错误(将之前LoadBalancerClient相关代码注释掉再进行测试):
8
在进行服务调用时,Spring Cloud拦截请求,通过负载均衡器从服务列表中选出节点,并替换服务名部分为具体的ip和端口,实现基于服务名的负载均衡调用。

4.WebClient服务调用

使用Spring WebFlux中的WebClient可以通过响应式编程的方式异步访问服务端接口。首先在服务消费者中引入依赖:

<!-- Spring Webflux 起步依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

创建WebClient.Bulider的Bean:

package com.rtxtitanv.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.config.WebClientConfig
 * @description WebClient配置类
 * @date 2021/5/1 18:21
 */
@Configuration
public class WebClientConfig {

    @LoadBalanced
    @Bean(name = "webClientBuilder")
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}

ConsumerController中新增以下方法:

@GetMapping("/test2")
public Mono<String> consumerTest2() {
    return consumerService.consumerTest2();
}

ConsumerService中新增以下方法:

Mono<String> consumerTest2();

ConsumerServiceImpl中实现该方法:

@Resource
private WebClient.Builder webClientBuilder;

@Override
public Mono<String> consumerTest2() {
    return webClientBuilder.baseUrl("http://nacos-discovery-provider").build().get().uri("/home").retrieve()
        .bodyToMono(String.class);
}

重新启动服务消费者后不断访问http://localhost:8080/test2
9
如果去掉服务消费者中的 spring-cloud-starter-loadbalancer依赖,则在服务调用的时候会报如下错误:
10
通过WebClient进行服务调用并实现负载均衡的实现原理在思想上与RestTemplate是相同的,都是通过添加相应的拦截器实现的。

5.OpenFeign服务调用

使用Spring Cloud OpenFeign可以进行声明式的服务调用。首先引入依赖:

<!-- Spring Cloud OpenFeign 起步依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

再在服务消费者主启动类上添加@EnableFeignClients注解。然后编写声明式REST服务调用接口:

package com.rtxtitanv.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.feignclient.OpenFeignClient
 * @description 声明式REST服务调用接口
 * @date 2021/5/1 16:41
 */
@FeignClient(value = "nacos-discovery-provider")
public interface OpenFeignClient {

    /**
     * 声明式REST服务调用接口方法,调用服务nacos-discovery-provider的/home
     * 
     * @return 调用nacos-discovery-provider返回的结果
     */
    @GetMapping("/home")
    String openFeignTest();
}

ConsumerController中新增以下方法:

@GetMapping("/test3")
public String consumerTest3() {
    return consumerService.consumerTest3();
}

ConsumerService中新增以下方法:

String consumerTest3();

ConsumerServiceImpl中实现该方法:

@Resource
private OpenFeignClient openFeignClient;

@Override
public String consumerTest3() {
    return openFeignClient.openFeignTest();
}

重新启动服务消费者后不断访问http://localhost:8080/test3
11
如果去掉服务消费者中的 spring-cloud-starter-loadbalancer依赖,则服务消费者在启动时会报如下错误:
12

6.服务分组

不同的服务可以归类到同一分组。通过spring.cloud.nacos.discovery.group可以设置服务所处的分组,该配置项默认值为DEFAULT_GROUP,如果服务没设置分组,则默认处于DEFAULT_GROUP。

首先在服务提供者的application.yml中新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 设置服务所处的分组,默认值为DEFAULT_GROUP
        group: DEV-GROUP

然后启动3个服务提供者实例与1个服务消费者实例,查看Nacos的管理页面中的服务列表:
13
服务提供者与服务消费者处于两个不同的分组,进行服务调用时会出错,这里以访问http://localhost:8080/test1为例,服务消费者中会报以下错误:
14
通过分组可以将不同分组的服务隔离开来,下面在服务消费者的application.yml中也新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 设置服务所处的分组,默认值为DEFAULT_GROUP
        group: DEV-GROUP

重启服务消费者,刷新Nacos的管理页面中的服务列表:
15
可见服务提供者与服务消费者已经处于同一个分组DEV-GROUP,不断访问http://localhost:8080/test1
16

7.命名空间

Nacos数据模型Key由三元组唯一确定,Namespace(命名空间)默认是空串,公共命名空间(public),分组默认是DEFAULT_GROUP
17
命名空间(Namespace)用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的Group或Data ID的配置。Namespace的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

在Nacos的管理页面中的命名空间菜单下新建dev,test,prod三个命名空间:
18
19
建立好所有命名空间后,在配置管理与服务管理模块下所有页面,都会包含用于切换命名空间的按钮:
20

注意:

  • 命名空间public是nacos的一个保留空间,如果需要创建自己的命名空间,不要和public重名,以一个实际业务场景有具体语义的名字来命名,以免带来字面上不容易区分自己是哪一个命名空间。
  • spring.cloud.nacos.discovery.namespace配置项的值为命名空间ID,而不是名称。

通过spring.cloud.nacos.discovery.namespace可以设置服务所处的命名空间,如果服务没设置命名空间,默认处于public命名空间。

首先在服务提供者的application.yml中新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 设置服务所处的命名空间,通过命名空间的ID来指定命名空间,这里设置为命名空间dev
        namespace: d8830907-76c9-4b18-a670-789f4290b8b5

在服务消费者的application.yml中新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 设置服务所处的命名空间,通过命名空间的ID来指定命名空间,这里设置为命名空间test
        namespace: 374a5221-33fb-47b7-8ca1-4b0955c81c4c

然后启动3个服务提供者实例与1个服务消费者实例,查看Nacos的管理页面中命名空间dev的服务列表:
21
查看Nacos的管理页面中命名空间test的服务列表:
22
服务提供者与服务消费者处于两个不同的命名空间,进行服务调用时会报与同一命名空间下不同分组之间的服务调用相同的错误,这里以访问http://localhost:8080/test1为例:
23
通过命名空间可以隔离不同环境下的资源(配置、服务),下面将服务消费者的命名空间设置改为命名空间dev的IDd8830907-76c9-4b18-a670-789f4290b8b5,重启服务消费者,刷新Nacos的管理页面中命名空间dev的服务列表:
24
可见服务提供者与服务消费者已经处于同一个命名空间dev,不断访问http://localhost:8080/test1
25

8.虚拟集群

服务领域模型是一种服务-集群-实例三层模型:
26

这里补充一下几个经常出现的概念的解释:

  • 服务:通过预定义接口网络访问的提供给客户端的软件功能。
  • 服务名:服务提供的标识,通过该标识可以唯一确定其指代的服务。
  • 实例:提供一个或多个服务的具有可访问网络地址(IP:Port)的进程。
  • 元信息:Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标签 (label),从作用范围来看,分为服务级别的元信息、集群的元信息及实例的元信息。
  • 权重:实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大。
  • 健康检查:以指定方式检查服务下挂载的实例(Instance)的健康度,从而确认该实例(Instance)是否能提供服务。根据检查结果,实例(Instance)会被判断为健康或不健康。对服务发起解析请求时,不健康的实例(Instance)不会返回给客户端。
  • 健康保护阈值:为了防止因过多实例(Instance)不健康导致流量全部流向健康实例(Instance),继而造成流量压力把健康实例(Instance)压垮并形成雪崩效应,应将健康保护阈值定义为一个0到1之间的浮点数。当域名健康实例(Instance)占总服务实例(Instance)的比例小于该值时,无论实例(Instance)是否健康,都会将这个实例(Instance)返回给客户端。这样做虽然损失了一部分流量,但是保证了集群的剩余健康实例(Instance)能正常工作。

同一个服务下的所有服务实例组成一个默认集群,集群可以被进一步按需求划分,划分的单位可以是虚拟集群。通过spring.cloud.nacos.discovery.cluster-name可以设置集群名称,相同集群下的实例才能互相感知。

在服务提供者的application.yml中新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 设置集群名称,默认值为DEFAULT
        cluster-name: ${CLUSTER_NAME:DEFAULT}

如下图所示方式启动集群名为PROVIDER1的三个服务提供者实例,端口分别为8091、8092、8093;启动集群名为PROVIDER2的三个服务提供者实例,端口分别为8094、8095、8096,然后再启动1个服务消费者实例:
27
启动后查看Nacos的管理页面中服务提供者所处的命名空间中的服务列表:
28
查看服务提供者详情信息:
29
不断访问http://localhost:8080/test1
30

9.服务管理

Nacos主页提供了一个服务管理菜单,能够查看、编辑当前注册的服务。服务管理菜单下的服务列表管理以统一的视图管理其所有的微服务以及服务健康状态。服务列表主要展示服务名、分组名称、集群数目、实例数、健康实例数等,点击详情可以看到服务的详情信息。重新启动3个服务提供者和1个服务消费者实例,均处于默认集群,两个服务都处于命名空间dev,服务列表信息如下:
31
在服务详情页面中可以修改实例的权重,权重为实例级别的配置,权重越大,分配给该实例的流量越大。如果不想实例接收流量,则可以将权重设为0:
32
不断访问http://localhost:8080/test1
33
将端口为8093的实例的权重改回1后,不断访问http://localhost:8080/test1,端口为8093的实例将会重新接收流量,这里省略测试截图。

通过spring.cloud.nacos.discovery.metadata可以自定义一些和服务相关的元数据信息,使用Map格式配置。

在服务提供者的application.yml中新增以下配置:

spring:
  cloud:
    nacos:
      discovery:
        # 自定义服务的元数据信息,使用Map格式配置
        metadata:
          app.name: nacos-discovery-provider
          app.version: 1.0.0
          app.author: rtxtitanv

重启服务提供者的实例,在服务列表页面查看详情,可见设置的是实例的元数据:
34
在服务详情中的编辑服务中可以自定义服务的元数据,这些元数据以k-v格式存储。下面在元数据输入框输入service.description=Service Provider
35
点击确认之后服务的元数据就已经更新:
36
Nacos还提供服务实例的上下线操作,在服务详情页面中可以点击实例的“上线”或者“下线”按钮,被下线的实例将不会接收访问流量。正常启动3个服务提供者实例与1个服务消费者实例之后,根据之前的截图,可知对于服务提供者,健康的实例个数为3。不断访问http://localhost:8080/test1,3个实例都会接收访问流量,下面将端口为8092的实例下线:
37
不断访问http://localhost:8080/test1,发现端口为8092的实例已不再接收流量:
38
然后将端口为8092的实例恢复上线状态,再不断访问http://localhost:8080/test1,端口为8092的实例会重新接收访问流量。

10.服务发现常用配置项

Spring Cloud Alibaba官方文档中列出的常用的关于spring-cloud-starter-alibaba-nacos-discovery的starter配置项如下所示:

配置项Key默认值说明
服务端地址spring.cloud.nacos.discovery.server-addrNacos Server启动监听的ip地址和端口
服务名spring.cloud.nacos.discovery.service${spring.application.name}给当前的服务命名
服务分组spring.cloud.nacos.discovery.groupDEFAULT_GROUP设置服务所处的分组
权重spring.cloud.nacos.discovery.weight1取值范围1到100,数值越大,权重越大
网卡名spring.cloud.nacos.discovery.network-interface当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址
注册的IP地址spring.cloud.nacos.discovery.ip优先级最高
注册的端口spring.cloud.nacos.discovery.port-1默认情况下不用配置,会自动探测
命名空间spring.cloud.nacos.discovery.namespace常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等
AccessKeyspring.cloud.nacos.discovery.access-key当要上阿里云时,阿里云上面的一个云账号名
SecretKeyspring.cloud.nacos.discovery.secret-key当要上阿里云时,阿里云上面的一个云账号密码
Metadataspring.cloud.nacos.discovery.metadata使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息
日志文件名spring.cloud.nacos.discovery.log-name
集群spring.cloud.nacos.discovery.cluster-nameDEFAULT配置成Nacos集群名称
接入点spring.cloud.nacos.discovery.enpointUTF-8地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
是否集成Ribbonribbon.nacos.enabledtrue一般都设置成true即可
是否开启Nacos Watchspring.cloud.nacos.discovery.watch.enabledtrue可以设置成false来关闭 watch

四、Nacos作为配置中心

在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如WAR,JAR包等)更好地和实际的物理运行环境进行适配。

Nacos提供用于存储配置和其他元数据的key/value存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用Spring Cloud Alibaba Nacos Config,可以在Nacos Server集中管理Spring Cloud应用的外部属性配置。

Nacos官方文档对配置相关概念的解释:

  • 配置项:一个具体的可配置的参数与其值域,通常以param-key=param-value的形式存在。
  • 配置集:一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。
  • 配置集ID:Nacos中的某个配置集的ID。配置集ID是组织划分配置的维度之一。Data ID通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID通常采用类Java包的命名规则保证全局唯一性。此命名规则非强制。
  • 配置分组:Nacos中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串对配置集进行分组,从而区分Data ID相同的配置集。当在Nacos上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认为DEFAULT_GROUP。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如database_url配置和MQ_topic配置。

1.发布配置

首先在Nacos添加如下配置:

Data ID:nacos-config-client.properties
Group:DEFAULT_GROUP
配置格式:Properties
配置内容:

user.name=Nero
user.age=20

方式1:在命令行执行如下命令,向 Nacos Server 中添加一条配置:

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos-config-client.properties&group=DEFAULT_GROUP&content=user.name=Nero%0Auser.age=20"

执行命令之后查看配置列表,可见配置文件创建成功:
39
方式2:启动Nacos Server后,首先在Nacos的配置列表页面中点击右边的+号:
40
进入新建配置页面新建配置文件:
41
点击发布并确定之后查看配置列表,可见配置文件创建成功:
42

2.创建Config客户端

SpringBoot、SpringCloud和SpringCloudAlibaba依赖这里就不列出来了,还需引入以下依赖:

<!-- Spring Cloud Alibaba Nacos Config 配置中心起步依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

主启动类这里就不贴出来了。编写配置文件,在bootstrap.yml里进行如下配置:

server:
  port: ${PORT:8000}

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      config:
        # nacos服务器地址
        server-addr: 127.0.0.1:8848

必须使用bootstrap配置文件来配置Nacos Server地址。这里spring.application.name值需与Nacos中创建的配置文件的Data Id匹配(除了.properties或者.yaml后缀)。因为dataId的完整格式为${prefix}-${spring.profiles.active}.${file-extension}prefix默认为spring.application.name的值,spring.profiles.active为当前环境对应的profile,这里该值为空,-也将不存在,dataId的拼接格式变成${prefix}.${file-extension}file-exetension为配置内容的数据格式,默认值为properties。所以这里要加载的配置文件的dataIdnacos-config-client.properties,与Nacos中创建的配置文件一致。

创建测试用的Controller:

package com.rtxtitanv.controller;

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

/**
 * @author rtxtitanv
 * @version 1.0.0
 * @name com.rtxtitanv.controller.ConfigClientController
 * @description ConfigClientController
 * @date 2021/5/5 18:15
 */
@RestController
@RefreshScope
public class ConfigClientController {

    @Value("${user.name:Unknown}")
    private String userName;
    @Value("${user.age:Unknown}")
    private String userAge;

    @GetMapping("/user")
    public String getUser() {
        return "user(userName=" + userName + ", userAge=" + userAge + ")";
    }
}

在服务成功启动后会从Nacos Config Server中获取相应的配置,并添加在Spring Environment的PropertySources中。使用@Value注解可以将对应的配置项注入到ConfigClientControlleruserNameuserAge字段,@RefreshScope实现配置动态刷新。

启动Config客户端服务,会发现并没有加载Bootstrap配置:
43
这是由于在SpringCloud 2020版,spring-cloud-commons提供的Bootstrap不再被默认启用。可以通过设置属性或引入一个新的启动器来启用Bootstrap上下文:

  • 通过属性重新启用,要设置spring.cloud.bootstrap.enabled=truespring.config.use-legacy-processing=true。这些属性需要作为环境变量、java系统属性或命令行参数来设置。
  • 另一种方式就是引入spring-cloud-starter-bootstrap依赖。

在VM options中添加-Dspring.cloud.bootstrap.enabled=true参数后可以启用Bootstrap上下文:
44
这里使用引入spring-cloud-starter-bootstrap依赖的方式,依赖如下:

<!-- 在SpringCloud 2020版,由于spring-cloud-commons提供的Bootstrap不再被默认启用
可以引入新的启动器来重新启用它 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

再次启动Config客户端服务会加载Bootstrap配置,部分启动日志截图如下:
45
访问http://localhost:8000/user,可见已经成功从Nacos Config Server获取到了配置文件中的数据:
46

3.支持配置的动态更新

spring-cloud-starter-alibaba-nacos-config也支持配置的动态更新。Nacos Config Starter默认为所有获取数据成功的Nacos的配置项添加了监听功能,在监听到服务端配置发生变化时会实时触发org.springframework.cloud.context.refresh.ContextRefresher的refresh方法。如果需要对Bean进行动态刷新,推荐给类添加@RefreshScope@ConfigurationProperties注解。

修改配置文件nacos-config-client.properties
47
发布确认之后,该配置中的user.age已被修改为21。再次访问http://localhost:8000/user,可见获取到了最新的数据:
48

可以通过配置spring.cloud.nacos.config.refresh.enabled=false来关闭动态刷新。

4.获取配置的规则

Nacos Config主要通过dataId和group来唯一确定一条配置。dataId的完整格式为${prefix}-${spring.profiles.active}.${file-extension}

  • prefix默认为spring.application.name的值,也可以通过配置项spring.cloud.nacos.config.prefix来配置。
  • spring.profiles.active即为当前环境对应的profile。当spring.profiles.active为空时,对应的连接符-也将不存在,dataId的拼接格式变成${prefix}.${file-extension}
  • file-exetension为配置内容的数据格式,默认值为properties,可以通过配置项spring.cloud.nacos.config.file-extension来配置。

group:

  • group默认为 DEFAULT_GROUP,可以通过spring.cloud.nacos.config.group配置。

前面的配置文件nacos-config-client.properties之所以能被加载,是因为使用默认值的服务加载配置的规则为dataId=${spring.application.name}.properties, group=DEFAULT_GROUP,正好是该配置文件。

下面在Nacos新发布一个配置:

Data ID:user-config.properties
Group:DEFAULT_GROUP
配置格式:Properties
配置内容:

user.name=Arthur
user.age=18

查看配置列表以及配置详情:
49
50
配置文件user-config.properties的dataId前缀与spring.application.name的值不同,所以需要通过spring.cloud.nacos.config.prefix可以指定dataId的prefixuser-config。在bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        # 指定dataId的prefix,默认值为spring.application.name的值
        # 这里确定要获取的配置文件的dataId的prefix为user-config
        prefix: user-config

重启Config客户端服务后访问http://localhost:8000/user,可见获取到的是配置文件user-config.properties中的数据:
51

5.指定配置格式

spring-cloud-starter-alibaba-nacos-config还支持yaml等多种配置格式。可以通过spring.cloud.nacos.config.file-extension来指定dataId的后缀,也是配置的文件格式,获取指定格式的配置。

首先在Nacos发布几个不同格式的配置文件:

Data ID:user-config.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: Sora
  age: 22

Data ID:user-config.xml
Group:DEFAULT_GROUP
配置格式:XML
配置内容:

<user>
    <name>John</name>
    <age>25</age>
</user>    

Data ID:user-config.json
Group:DEFAULT_GROUP
配置格式:JSON
配置内容:

{
 "user": {
     "name": "William",
     "age": 23
 }
}    

查看配置列表以及3个配置的详情:
52
53
在Config客户端服务的bootstrap.yml配置文件中显示的声明dataId文件扩展名:

spring:
  cloud:
    nacos:
      config:
        # 指定dataId的后缀,同时也是配置的文件格式,默认值为properties
        # 这里确定要获取的配置文件的格式为yaml
        file-extension: yaml

重启Config客户端服务后访问http://localhost:8000/user,可见获取到的是配置文件user-config.yaml中的数据:
54
spring.cloud.nacos.config.file-extension设置为xml后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是配置文件user-config.xml中的数据:
55
spring.cloud.nacos.config.file-extension设置为json后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是配置文件user-config.json中的数据:
56
最后将spring.cloud.nacos.config.file-extension改回yaml以便于之后的测试。

6.profile粒度的配置

dataId的完整格式为${prefix}-${spring.profiles.active}.${file-extension},之前加载了dataId为${prefix}.${file-extension}的基础配置,是因为没有通过spring.profiles.active配置环境,spring.profiles.active的值为空,连接符-也就不存在,dataId的拼接格式就变成了${prefix}.${file-extension}。如果需要在不同环境下使用不同配置,可以通过配置项spring.profiles.active来配置。

首先在Nacos发布3个应用于不同环境下的配置:

Data ID:user-config-dev.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: dev-user
  age: 20

Data ID:user-config-test.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: test-user
  age: 21

Data ID:user-config-prod.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: prod-user
  age: 22

查看配置列表以及3个配置的详情:
57
58
bootstrap.yml中新增以下配置:

spring:
  profiles:
    # 配置当前环境对应的profile为dev
    active: dev

这里是在配置文件中配置spring.profiles.active=<profilename>,而在实际项目实施过程中该变量的值是需要不同环境下有不同的值。这时通常是通过 -Dspring.profiles.active=<profile> 参数指定其配置来达到环境间灵活的切换。

重启Config客户端服务后访问http://localhost:8000/user,可见获取到的是配置文件user-config-dev.yaml中的数据:
59
spring.profiles.active设置为test后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是配置文件user-config-test.yaml中的数据:
60
spring.profiles.active设置为prod后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是配置文件user-config-prod.yaml中的数据:
61
最后将spring.profiles.active配置注释掉以便于之后的测试。

7.自定义Group的配置

在没有明确指定${spring.cloud.nacos.config.group}配置的情况下,默认使用的Group是DEFAULT_GROUP 。通过配置项spring.cloud.nacos.config.group可以指定自定义的Group。

首先在Nacos发布3个处于不同Group的配置:

Data ID:user-config.yaml
Group:DEV_GROUP
配置格式:YAML
配置内容:

user:
  name: dev-group-user
  age: 23

Data ID:user-config.yaml
Group:TEST_GROUP
配置格式:YAML
配置内容:

user:
  name: test-group-user
  age: 24

Data ID:user-config.yaml
Group:PROD_GROUP
配置格式:YAML
配置内容:

user:
  name: prod-group-user
  age: 25

查看配置列表以及3个配置的详情,可知这三个配置文件dataId相同,但Group不同:
62
63
要获取这三个配置文件中的任意一个,都需要指定它所属的Gruop,不然会获取属于DEFAULT_GROUP的user-config.yaml。下面在bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        # 指定Group,默认值为DEFAULT_GROUP
        # 这里确定要获取的配置文件所属Group为DEV_GROUP
        group: DEV_GROUP

该配置必须放在bootstrap配置文件中,并且在添加配置时Group的值一定要和spring.cloud.nacos.config.group的配置值一致。

重启Config客户端服务后访问http://localhost:8000/user,可见获取到的是属于DEV_GROUP的配置文件user-config.yaml中的数据:
64
spring.cloud.nacos.config.group设置为TEST-GROUP后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是属于TEST-GROUP的配置文件user-config.yaml中的数据:
65
spring.cloud.nacos.config.group设置为PROD_GROUP后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是属于PROD_GROUP的配置文件user-config.yaml中的数据:
66
最后将spring.cloud.nacos.config.group注释掉以便于之后的测试。

8.自定义Namespace的配置

在没有明确指定${spring.cloud.nacos.config.namespace}配置的情况下, 默认使用的是Nacos上Public这个namespae(命名空间),通过配置项spring.cloud.nacos.config.namespace可以指定要使用的自定义的命名空间。之前创建的3个命名空间如下:
67
在命名空间dev发布如下配置:

Data ID:user-config.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: dev-namespace-user
  age: 26

在命名空间test发布如下配置:

Data ID:user-config.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: test-namespace-user
  age: 27

在命名空间prod发布如下配置:

Data ID:user-config.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: prod-namespace-user
  age: 28

创建成功之后查看这3个命名空间的配置列表以及3个配置的详情,可见3个配置文件的dataId和group均相同,但分别处于3个不同的命名空间:
68
69
要获取这三个配置文件中的任意一个,都需要指定它所属的Namespace,不然会获取属于命名空间public的user-config.yaml。下面在bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        # 指定命名空间,必须通过命名空间的ID来指定,默认使用Nacos的public命名空间
        # 这里确定要获取的配置文件所属的Namespace为dev
        namespace: d8830907-76c9-4b18-a670-789f4290b8b5

该配置必须放在bootstrap配置文件中。spring.cloud.nacos.config.namespace的值是namespace对应的id,id值可以在Nacos的控制台获取。并且在添加配置时注意不要选择其他的namespae,否则将会导致读取不到正确的配置。

重启Config客户端服务后访问http://localhost:8000/user,可见获取到的是命名空间dev中的配置文件user-config.yaml中的数据:
70
spring.cloud.nacos.config.namespace设置为374a5221-33fb-47b7-8ca1-4b0955c81c4c后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是命名空间test中的配置文件user-config.yaml中的数据:
71
spring.cloud.nacos.config.namespace设置为35be3a75-f528-4f10-b38f-acfaf1f1d4f5后重启Config客户端服务,访问http://localhost:8000/user,可见获取到的是命名空间prod中的配置文件user-config.yaml中的数据:
72
最后将spring.cloud.nacos.config.namespace改回命名空间dev的id便于之后的测试。

9.自定义扩展的Data Id配置

Spring Cloud Alibaba Nacos Config支持自定义Data Id的配置。通过自定义扩展的Data Id配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。

首先在命名空间dev发布3个配置:

Data ID:ext-config-common-test1.properties
Group:DEFAULT_GROUP
配置格式:Properties
配置内容:

common.host=127.0.0.1
common.username=root
common.password=root

Data ID:ext-config-common-test2.yaml
Group:GLOBALE_GROUP
配置格式:YAML
配置内容:

common:
  host: 192.168.221.16
  port: 6379
  password: 123456

Data ID:ext-config-common-test3.json
Group:REFRESH_GROUP
配置格式:JSON
配置内容:

{
 "common": {
     "port": "3306",
     "password": "abcdef"
 }
}

73
ConfigClientController中新增如下代码:

@Value("${common.host:Unknown}")
private String commonHost;
@Value("${common.port:Unknown}")
private String commonPort;
@Value("${common.username:Unknown}")
private String commonUsername;
@Value("${common.password:Unknown}")
private String commonPassword;    

@GetMapping("/ext-config")
public String getExtConfig() {
    return "common.host: " + commonHost + ", common.port: " + commonPort + ", common.username: " + commonUsername
        + ", common.password: " + commonPassword;
}

bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        # 自定义扩展的dataId配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件
        extension-configs:
          # dataId在默认的组DEFAULT_GROUP,不支持配置动态刷新
          - data-id: ext-config-common-test1.properties
          # dataId在GLOBALE_GROUP分组,不支持配置动态刷新
          - data-id: ext-config-common-test2.yaml
            # 配置dataId所在分组,缺省默认DEFAULT_GROUP
            group: GLOBALE_GROUP
          # dataId在REFRESH_GROUP分组,支持配置动态刷新
          - data-id: ext-config-common-test3.json
            group: REFRESH_GROUP
            # 配置dataId在配置变更时,是否支持动态刷新,缺省默认false
            refresh: true

多个Data Id同时配置时,优先级关系是spring.cloud.nacos.config.extension-configs数组下标值越大,优先级越高。spring.cloud.nacos.config.extension-configs[n].data-id的值必须带文件扩展名,spring.cloud.nacos.config.file-extension的配置对自定义扩展配置的Data Id文件扩展名没有影响。

重启Config客户端服务,除了加载了通过内部规则${prefix}-${spring.profiles.active}.${file-extension}自动生成的dataId为user-config.yaml的配置外,通过spring.cloud.nacos.config.extension-configs配置的3个配置文件也被加载:
74
访问http://localhost:8000/ext-config
75
根据返回的结果可以验证,spring.cloud.nacos.config.extension-configs配置的多个Data Id有相同的配置项时,优先级关系是spring.cloud.nacos.config.extension-configs数组下标值越大,优先级越高。修改配置文件ext-config-common-test3.json下的common.password
76
访问http://localhost:8000/ext-config,由于配置了ext-config-common-test3.json在变更时支持动态刷新,所以获取到了最新的值:
77
修改ext-config-common-test2.yamlcommon.host
78
访问http://localhost:8000/ext-config,由于未配置dataId为ext-config-common-test2.yamlrefresh,默认不支持动态刷新,获取不到变更后的值:
79
可以通过spring.cloud.nacos.config.shared-configs更加清晰的在多个应用间配置共享Data Id。下面在命名空间dev发布3个配置:

Data ID:share-config-test1.properties
Group:DEFAULT_GROUP
配置格式:Properties
配置内容:

share.username=root
share.hostname=share-server
log.level=warning

Data ID:share-config-test2.yaml
Group:GLOBALE_GROUP
配置格式:YAML
配置内容:

share:
  username: admin
  password: 123456
log:
  level: info

Data ID:share-config-test3.json
Group:REFRESH_GROUP
配置格式:JSON
配置内容:

{
 "share": {
     "password": "admin"
 }
 "log": {
     "level": "debug"
 }
}

80
ConfigClientController中新增如下代码:

@Value("${share.username:Unknown}")
private String shareUsername;
@Value("${share.password:Unknown}")
private String sharePassword;
@Value("${share.hostname:Unknown}")
private String shareHostname;
@Value("${log.level:Unknown}")
private String logLevel;

@GetMapping("/share-config")
public String getShareConfig() {
    return "share.username: " + shareUsername + ", share.password: " + sharePassword + ", share.hostname: "
        + shareHostname + ", log.info: " + logLevel;
}

bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        # 配置共享的dataId
        shared-configs:
          # dataId在默认的组DEFAULT_GROUP,不支持配置动态刷新
          - data-id: share-config-test1.properties
          # dataId在GLOBALE_GROUP分组,不支持配置动态刷新
          - data-id: share-config-test2.yaml
            # 配置dataId所在分组,缺省默认DEFAULT_GROUP
            group: GLOBALE_GROUP
          # dataId在REFRESH_GROUP分组,支持配置动态刷新
          - data-id: share-config-test3.json
            group: REFRESH_GROUP
            # 配置dataId在配置变更时,是否支持动态刷新,缺省默认false
            refresh: true

重启Config客户端服务,发现通过spring.cloud.nacos.config.shared-configs配置的共享配置文件会被加载:
81
访问http://localhost:8000/share-config
82
根据返回的结果可以验证,spring.cloud.nacos.config.shared-configs配置的多个Data Id有相同的配置项时,优先级关系是spring.cloud.nacos.config.shared-configs数组下标值越大,优先级越高。spring.cloud.nacos.config.shared-configs[n].refreshspring.cloud.nacos.config.extension-configs[n].refresh都是来控制该Data Id在配置变更时,是否支持应用中动态刷新,默认false,关于共享dataId的配置的动态刷新的测试结果和自定义扩展dataId的配置类似,这里就省略了。

10.配置的优先级

Spring Cloud Alibaba Nacos Config目前提供了三种配置能力从Nacos拉取相关的配置。

  • A:通过 spring.cloud.nacos.config.shared-configs[n].data-id 支持多个共享 Data Id 的配置。
  • B:通过 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多个扩展 Data Id 的配置。
  • C:通过内部相关规则(${prefix}-${spring.profiles.active}.${file-extension}spring.cloud.nacos.config.group)自动生成相关的Data Id配置。

当三种方式共同使用时,他们的一个优先级关系是:A < B < C。

下面来验证一下,先在命名空间dev发布2个配置:

Data ID:priority-extension-configs.yaml
Group:REFRESH_GROUP
配置格式:YAML
配置内容:

user:
  name: admin
  age: 20
log:
  level: debug

Data ID:priority-shared-configs.yaml
Group:REFRESH_GROUP
配置格式:YAML
配置内容:

user:
  name: root
  pwd: 123456
log:
  level: info

通过内部相关规则自动生成的Data Id的配置,位于命名空间dev(该配置是之前创建的):

Data ID:user-config.yaml
Group:DEFAULT_GROUP
配置格式:YAML
配置内容:

user:
  name: dev-namespace-user
  age: 26

83
ConfigClientController中新增如下代码:

@Value("${user.pwd:Unknown}")
private String userPwd;

@GetMapping("/priority")
public String configPriority() {
    return "user.name: " + userName + ", user.age: " + userAge + ", user.pwd: " + userPwd + ", log.info: "
        + logLevel;
}

bootstrap.yml中新增以下配置:

spring:
  cloud:
    nacos:
      config:
        extension-configs:
          # 该dataId配置用于测试配置优先级
          - data-id: priority-extension-configs.yaml
            group: REFRESH_GROUP
            refresh: true
        shared-configs:
          # 该dataId配置用于测试配置优先级
          - data-id: priority-shared-configs.yaml
            group: REFRESH_GROUP
            refresh: true

重启Config客户端服务,访问http://localhost:8000/priority
84
根据以上结果可知,3种类型的配置均有user.name,而最终获取到的user.name的结果为user-config.yamluser.name的值,说明C的优先级最高,而A和B均有log.level,而最终获取到的log.level的结果为priority-extension-configs.yamllog.level的值,说明B的优先级高于A,所以综上可知优先级顺序为A < B < C。

通过设置spring.cloud.nacos.config.enabled = false来完全关闭 Spring Cloud Nacos Config。

代码示例

  • 5
    点赞
  • 6
    评论
  • 5
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论 6 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

RtxTitanV

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值