Version

cloud-alibaba-2024 版本控制

版本日志

名称版本
Java17
Maven3.8.1
Spring Boot2.6.15
Spring Cloud2021.0.9
Spring Cloud Alibaba2021.0.6.0
Nacos Server2.3.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.study</groupId>
    <artifactId>cloud-alibaba-2024</artifactId>
    <version>1.0</version>
    <packaging>pom</packaging>
 
    <description>学习 Spring Cloud Alibaba</description>
 
    <modules>
        <module>nacos-provider-9001</module>
        <module>nacos-consumer-9003</module>
        <module>nacos-config-9004</module>
    </modules>
 
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.15</spring-boot.version>
        <spring-cloud.version>2021.0.9</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.0.6.0</spring-cloud-alibaba.version>
    </properties>
 
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
 
            <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>
 
            <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.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
 
</project>
 
指向原始笔记的链接

Question

  • 在配置文件中配置了 spring.cloud.nacos.config.server-addr,启动类没有添加 @EnableDiscoveryClient。这种情况下,Nacos 控制台可以看到服务注册成功了。为什么会成功呢?@EnableDiscoveryClient 注解的作用到底是什么?

注册中心

创建子模块 nacos-provider-9001

  1. 引入 spring-cloud-starter-alibaba-nacos-discovery 依赖
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <parent>
        <groupId>com.study</groupId>
        <artifactId>cloud-alibaba-2024</artifactId>
        <version>1.0</version>
    </parent>
 
    <artifactId>nacos-provider-9001</artifactId>
    <packaging>jar</packaging>
    <name>nacos-provider-9001</name>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Nacos 注册中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.study.provider.ProviderApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  1. 配置 Nacos Server 地址
server:  
  port: 9001
spring:  
  application:  
    name: provider # 当前服务的名称  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 127.0.0.1:8848 # Nacos Server 地址
  1. 启动类,添加 @EnableDiscoveryClient 开启服务注册
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(ProviderApplication.class, args);  
    }  
}
  1. 测试接口
@RestController
@RequestMapping("env")
public class EnvController {
 
    @Autowired
    private Environment env;
 
    @GetMapping("getServerPort")
    public Map<String, String> getServerPort() {
        return Map.of("serverPort", env.getProperty("server.port"));
    }
}
  1. 启动服务后,在 Nacos 控制台可以看到服务注册成功

负载均衡

创建服务 Provider 9002

复制 Provider 9001 的启动配置,修改端口为 9002

RestTemplate

创建子模块 nacos-consumer-9003
  1. 添加 spring-cloud-starter-alibaba-nacos-discoveryspring-cloud-starter-loadbalancer 依赖
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>com.study</groupId>
        <artifactId>cloud-alibaba-2024</artifactId>
        <version>1.0</version>
    </parent>
    
    <artifactId>nacos-consumer-9003</artifactId>
    <packaging>jar</packaging>
    <name>nacos-consumer-9003</name>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
 
        <!--Spring Cloud 2020 版本以后,默认移除了对 Netflix 的依赖,loadbalancer 取缔了 Netflix 的 Ribbon
    loadbalancer 成为了 Spring Cloud 负载均衡器的唯一实现
    -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
    </dependencies>
</project>
  1. 配置 Nacos Server 地址
server:
  port: 9003
spring:
  application:
    name: consumer # 当前服务的名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos Server 地址
  1. 启动类,测试接口
@EnableDiscoveryClient
@SpringBootApplication
public class ConsumerApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
 
    // 给 RestTemplate 实例添加 @LoadBalanced 注解,
    // 开启 @LoadBalanced 与 Ribbon 的集成:
    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
 
    @RestController
    public class TestController {
 
        private final RestTemplate restTemplate;
 
        @Autowired
        public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;}
 
        @GetMapping("getServerPort")
        public Map<String, String> getServerPort() {
            // 将要访问的微服务名称
            String serviceName = "http://provider";
            return restTemplate.getForObject(serviceName + "/env/getServerPort", Map.class);
        }
    }
}
负载均衡测试

启动 Provider 9001、Provider 9002、Consumer 9003 服务。

测试 http://localhost:9003/getServerPort 接口,可以看到默认的负载均衡策略是轮询

配置中心

创建子模块 nacos-config-9004

  1. pom.xml
<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>com.study</groupId>
        <artifactId>cloud-alibaba-2024</artifactId>
        <version>1.0</version>
    </parent>
    
    <artifactId>nacos-config-9004</artifactId>
    <packaging>jar</packaging>
    <name>nacos-config-9004</name>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
		<!-- 配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
 
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>
</project>
 
  1. application.yml
server:
  port: 9004
spring:
  application:
    name: nacos-config
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务地址
      config:
        server-addr: 127.0.0.1:8848 # Nacos 服务地址
        file-extension: yaml # 指定 yaml 格式的配置
  config:
    import:
      - nacos:nacos-config-dev.yaml?refreshEnabled=true

springc.config.import 引入

说明:之所以需要配置 spring.application.name ,是因为它是构成 Nacos 配置管理 dataId 字段的一部分。

在 Nacos Spring Cloud 中,dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}
  • prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置。
  • spring.profiles.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。 注意:当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
  • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
  1. 启动类
@EnableDiscoveryClient
@SpringBootApplication
public class ConfigApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
    }
}
  1. 测试接口,通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新。
@RefreshScope
@RestController
public class NacosConfigController {
 
    @Value("${config.info}")
    private String configInfo;
 
    @GetMapping("/get-config-info")
    public String getConfigInfo() {
        return configInfo;
    }
}

Nacos 客户端添加配置信息

  1. 创建

  2. 编辑

  3. 发布

测试动态刷新

启动 nacos-config-9004 服务,修改 nacos-config-dev.yaml 配置测试动态刷新。

进阶

profile 粒度的配置

在日常开发中如果遇到多套环境下的不同配置,可以通过 Spring 提供的 ${spring.profiles.active} 这个配置项选择不同情况下的配置。

spring.profiles.active=develop

Nacos 上新增一个 dataId 为:nacos-config-develop.yaml 的基础配置,如下所示:

Data ID: nacos-config-develop.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容: current.env: develop-env

如果需要切换到生产环境,只需要更改 ${spring.profiles.active} 参数配置即可。如下所示:

spring.profiles.active=product

同时生产环境上 Nacos 需要添加对应 dataId 的基础配置。例如,在生成环境下的 Nacos 添加了 dataId 为:nacos-config-product.yaml 的配置:

Data ID: nacos-config-product.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置内容: current.env: product-env

Note

此案例中我们通过 spring.profiles.active=<profilename> 的方式写死在配置文件中,而在真正的项目实施过程中这个变量的值是需要不同环境而有不同的值。这个时候通常的做法是通过 -Dspring.profiles.active=<profile> 参数指定其配置来达到环境间灵活的切换。

自定义 Namespace 的配置

Namespace(命名空间) 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

在没有明确指定 ${spring.cloud.nacos.config.namespace} 配置的情况下, 默认使用的是 Nacos 中 public 命名空间即默认的命名空间。如果需要使用自定义的命名空间,可以通过以下配置来实现:

spring.cloud.nacos.config.namespace=YOUR_NAMESPACE_ID

Note

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

示例:

application.yml

server:
  port: 9004
spring:
  application:
    name: nacos-config
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 # Nacos 服务地址
      config:
        namespace: 0edc89e5-b63a-403d-a855-ab4332af9db3 # 命名空间
        server-addr: 127.0.0.1:8848 # Nacos 服务地址
        file-extension: yaml # 指定yaml格式的配置
  config:
    import:
      - nacos:nacos-config-dev.yaml?refreshEnabled=true

自定义 Group 的配置

在没有明确指定 ${spring.cloud.nacos.config.group} 配置的情况下, 默认使用的是组 DEFAULT_GROUP 。如果需要自定义 Group,可以通过以下配置来实现:

spring.cloud.nacos.config.group=YOUR_GROUP_NAME

Note

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

配置的优先级

Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置:

  • A: 通过 spring.cloud.nacos.config.shared-dataids 支持多个共享 Data Id 的配置

  • B: 通过 spring.cloud.nacos.config.ext-config[n].data-id 的方式支持多个扩展 Data Id 的配置

  • C: 通过内部相关规则 (应用名、应用名 + Profile ) 自动生成相关的 Data Id 配置

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

springc.config.import 引入

这里假设有一个配置文件 bootstrap.yml,升级到 2021.0.1.0 以上的版本应该怎么配置呢?

bootstrap.yml

spring:
  cloud:
    nacos:
      config:
        name: test.yml
        group: DEFAULT_GROUP
        server-addr: 127.0.0.1:8848
        extension-configs:
          - dataId: test01.yml
            group: group_01
          - dataId: test02.yml
            group: group_02
            refresh: false

注意:上面的配置和下面的配置是等价的!

application.yml

spring:
  cloud:
    nacos:
      config:
        group: DEFAULT_GROUP
        server-addr: 127.0.0.1:8848
  config:
    import:
      - optional:nacos:test.yml # 监听 DEFAULT_GROUP:test.yml
      - optional:nacos:test01.yml?group=group_01 # 覆盖默认 group,监听 group_01:test01.yml
      - optional:nacos:test02.yml?group=group_02&refreshEnabled=false # 不开启动态刷新
      - nacos:test03.yml # 在拉取nacos配置异常时会快速失败,会导致 spring 容器启动失败

使用 spring.config.import 引入配置时的注意事项如下:

  1. 如果使用 spring.config.import 就不能使用 bootstrap.yml / properties 引入配置的方式了;
  2. 如果引入了 spring-cloud-starter-alibaba-nacos-config,并且使用 import 方式导入配置, 项目启动时会自动检测是否引入了 nacos 条目,如果没有 import nacos 条目,会出现如下错误:
The spring.config.import property is missing a nacos: entry

Action:

Add a spring.config.import=nacos: property to your configuration.
If configuration is not required add spring.config.import=optional:nacos: instead.
To disable this check, set spring.cloud.nacos.config.import-check.enabled=false.

可以通过手动设置 spring.cloud.nacos.config.import-check.enabled=false 关闭它,但是不建议这么做,这个功能可以帮助你检查是否引入多余依赖

假如想保留以前的使用方式 ( bootstrap 引入配置),你只需要添加依赖 spring-cloud-starter-bootstrap 依赖,不需要修改一行代码即可完成配置方式的切换!

配置项参考

注册中心 spring.cloud.nacos.discovery 配置中心 spring.cloud.nacos.config

参考