假如我们有一个简单项目(nacos_multi_env2),该项目需要在开发环境(dev)和生产环境(prod)运行,但是有一些配置是公共的,我们需要将公共配置提取到单独一个配置文件中,同时应用到开发和生产环境。如下图:

在 Nacos 中创建 nacos_multi_env3 命名空间,然后在该命名空间中创建 public、example-dev 和 example-prod 三个配置集,如下图:

其中,public 配置集内容如下:
name=public
example-dev 配置集内容如下:
type=dev
example-prod 配置集内容如下:
type=prod
使用 IDEA 创建一个 Spring Boot 项目,项目结构图如下:

该项目存在三个 properties 配置文件,内容分别如下:
# 激活生产环境 spring.profiles.active=prod # 指定 Nacos 服务地址 nacos.config.server-addr=127.0.0.1:8848 # 指定 Nacos 命名空间 nacos.config.namespace=a9ab2d48-efb2-475e-a9c4-9064f59a8225 nacos.config.username=nacos nacos.config.password=nacos
# 没有
# 没有
一个简单的控制器,通过 @NacosValue 注解注入 type 和 name 配置项,代码如下:
package com.hxstrive.nacos;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
@Controller
@RequestMapping("config")
public class ConfigController {
   @NacosValue(value = "${type:}", autoRefreshed = true)
   private String type;
   @NacosValue(value = "${name:}", autoRefreshed = true)
   private String name;
   @RequestMapping(value = "/get", method = GET)
   @ResponseBody
   public String get() {
       return toString();
   }
   @Override
   public String toString() {
       return "ConfigController{" +
               "type='" + type + '\'' +
               ", name='" + name + '\'' +
               '}';
   }
}项目的启动类,使用 @NacosPropertySource 注解加载 dataId 为 “example + ${spring.profiles.active}” 的配置源,并开启自动更新。不过,该类存在两个 @NacosPropertySource,其中还加载了 public 配置源。
代码如下:
package com.hxstrive.nacos;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@NacosPropertySource(dataId = "example-${spring.profiles.active}", autoRefreshed = true)
@NacosPropertySource(dataId = "public", autoRefreshed = true)
public class MainApplication {
   public static void main(String[] args) {
       SpringApplication.run(MainApplication.class, args);
   }
}运行 MainApplication 类,启动项目,项目启动成功后,通过浏览器访问 http://localhost:8080/config/get  地址,输出如下:

通过上面的输出信息可知,Nacos 成功的加载了 public 和 example-prod 配置源,并且能够正确的获配置项。
如果 public 和 example-prod 配置集中存在同名的 key,那么 nacos 会怎么解析呢?其中,public 配置集内容如下:
name=public
example-dev 配置集内容如下:
type=dev name=dev-name
example-prod 配置集内容如下:
type=prod name=prod-name
代码如下:
package com.hxstrive.nacos;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@NacosPropertySource(dataId = "public", autoRefreshed = true)
@NacosPropertySource(dataId = "example-${spring.profiles.active}", autoRefreshed = true)
public class MainApplication {
   public static void main(String[] args) {
       SpringApplication.run(MainApplication.class, args);
   }
}启动项目,访问 http://localhost:8080/config/get 地址,输出如下:

从输出可以看出,name 并没有被 @NacosPropertySource(dataId = "example-${spring.profiles.active}", autoRefreshed = true) 加载的配置源覆盖。
如果我们将两个 @NacosPropertySource 注解调换顺序,代码如下:
package com.hxstrive.nacos;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@NacosPropertySource(dataId = "example-${spring.profiles.active}", autoRefreshed = true)
@NacosPropertySource(dataId = "public", autoRefreshed = true)
public class MainApplication {
   public static void main(String[] args) {
       SpringApplication.run(MainApplication.class, args);
   }
}启动项目,访问 http://localhost:8080/config/get 地址,输出如下:

通过上面输出可知,将会获取第一个 @NacosPropertySource 注解的配置源中的配置。
注意:Nacos 中,每一个 @NacosPropertySource 都被解析为一个 PropertySource 对象,并且将该对象添加到 Environment 的 propertySources 集合中,这个集合是 List 对象,默认每新增一个 PropertySource 对象,都会将其添加到集合的末尾,我们可以通过 NacosPropertySource 中的 first、before 等属性设置它们的顺序。
