== Spring Cloud Alibaba Nacos Config Nacos 是一个 Alibaba 开源的、易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 使用 Spring Cloud Alibaba Nacos Config,可基于 Spring Cloud 的编程模型快速接入 Nacos 配置管理功能。 === 如何引入 Nacos Config 进行配置管理 如果要在您的项目中使用 Nacos 来实现配置管理,使用 group ID 为 `com.alibaba.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-nacos-config` 的 starter。 [source,xml,indent=0] ---- com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config ---- === 快速开始 Nacos Config 使用 DataId 和 GROUP 确定一个配置。 下图表示 DataId 使用 `myDataid`, GROUP 使用 `DEFAULT_GROUP`,配置格式为 Properties 的一个配置项: .Nacos Config Item image::https://img.alicdn.com/tfs/TB1Yli3bUY1gK0jSZFMXXaWcVXa-2436-1138.png[] ==== Nacos 服务端初始化 具体启动方式参考 Spring Cloud Alibaba Nacos Discovery 小节的 "Nacos Server 启动" 章节。 Nacos Server 启动完毕后,添加如何配置: [source,subs="normal"] ---- Data ID: nacos-config.properties Group : DEFAULT_GROUP 配置格式: Properties 配置内容: user.name=nacos-config-properties user.age=90 ---- NOTE: 注意DataId是以 properties(默认的文件扩展名方式)为扩展名。 ==== 客户端使用方式 如果要在您的项目中使用 Nacos 来实现应用的外部化配置,使用 group ID 为 `com.alibaba.cloud` 和 artifact ID 为 `spring-cloud-starter-alibaba-nacos-config` 的 starter。 [source,xml] ---- com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config ---- 现在创建一个标准的 Spring Boot 应用。 [source,java] ---- @SpringBootApplication public class NacosConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :"+userName+"; age: "+userAge); } } ---- 在运行此 NacosConfigApplication 之前, 必须使用 `bootstrap.properties` 配置文件来配置 Nacos Server 地址,例如: .bootstrap.properties [source,properties] ---- # DataId 默认使用 `spring.application.name` 配置跟文件扩展名结合(配置格式默认使用 properties), GROUP 不配置默认使用 DEFAULT_GROUP。因此该配置文件对应的 Nacos Config 配置的 DataId 为 nacos-config.properties, GROUP 为 DEFAULT_GROUP spring.application.name=nacos-config spring.cloud.nacos.config.server-addr=127.0.0.1:8848 ---- NOTE: 注意当你使用域名的方式来访问 Nacos 时,`spring.cloud.nacos.config.server-addr` 配置的方式为 `域名:port`。 例如 Nacos 的域名为abc.com.nacos,监听的端口为 80,则 `spring.cloud.nacos.config.server-addr=abc.com.nacos:80`。 注意 80 端口不能省略。 启动这个 Example,可以看到如下输出结果: [source,subs="normal"] ---- 2018-11-02 14:24:51.638 INFO 32700 --- [main] c.a.demo.provider.ConfigApplication : Started ConfigApplication in 14.645 seconds (JVM running for 15.139) user name :nacos-config-properties; age: 90 2018-11-02 14:24:51.688 INFO 32700 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a8c5e74: startup date [Fri Nov 02 14:24:51 CST 2018]; root of context hierarchy ---- === 基于 DataId 为 yaml 的文件扩展名配置方式 Nacos Config 除了支持 properties 格式以外,也支持 yaml 格式。这个时候只需要完成以下两步: 1、在应用的 bootstrap.properties 配置文件中显示的声明 DataId 文件扩展名。如下所示 .bootstrap.properties [source,yaml] ---- spring.cloud.nacos.config.file-extension=yaml ---- 2、在 Nacos 的控制台新增一个DataId为yaml为扩展名的配置,如下所示: [source,subs="normal"] ---- Data ID: nacos-config.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: user.name: nacos-config-yaml user.age: 68 ---- 这两步完成后,重启测试程序,可以看到如下输出结果。 [source,subs="normal"] ---- 2018-11-02 14:59:00.484 INFO 32928 --- [main] c.a.demo.provider.ConfigApplication:Started ConfigApplication in 14.183 seconds (JVM running for 14.671) user name :nacos-config-yaml; age: 68 2018-11-02 14:59:00.529 INFO 32928 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@265a478e: startup date [Fri Nov 02 14:59:00 CST 2018]; root of context hierarchy ---- === 支持配置的动态更新 Nacos Config 默认支持配置的动态更新,启动 Spring Boot 应用测试的代码如下: [source,java] ---- @SpringBootApplication public class ConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); while(true) { //当动态配置刷新时,会更新到 Enviroment中,因此这里每隔一秒中从Enviroment中获取配置 String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); System.err.println("user name :" + userName + "; age: " + userAge); TimeUnit.SECONDS.sleep(1); } } } ---- 如下所示,当变更user.name时,应用程序中能够获取到最新的值: [source,subs="normal"] ---- user name :nacos-config-yaml; age: 68 user name :nacos-config-yaml; age: 68 user name :nacos-config-yaml; age: 68 2018-11-02 15:04:25.069 INFO 32957 --- [-127.0.0.1:8848] o.s.boot.SpringApplication : Started application in 0.144 seconds (JVM running for 71.752) 2018-11-02 15:04:25.070 INFO 32957 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@10c89124: startup date [Fri Nov 02 15:04:25 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@6520af7 2018-11-02 15:04:25.071 INFO 32957 --- [-127.0.0.1:8848] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6520af7: startup date [Fri Nov 02 15:04:24 CST 2018]; root of context hierarchy //从 Enviroment 中 读取到更改后的值 user name :nacos-config-yaml-update; age: 68 user name :nacos-config-yaml-update; age: 68 ---- NOTE: 你可以通过配置 `spring.cloud.nacos.config.refresh.enabled=false` 来关闭动态刷新 === 支持profile粒度的配置 Nacos Config 在加载配置的时候,不仅仅加载了以 DataId 为 `${spring.application.name}.${file-extension:properties}` 为前缀的基础配置,还加载了DataId为 `${spring.application.name}-${profile}.${file-extension:properties}` 的基础配置。在日常开发中如果遇到多套环境下的不同配置,可以通过Spring 提供的 `${spring.profiles.active}` 这个配置项来配置。 [source,properties] ---- spring.profiles.active=develop ---- NOTE: ${spring.profiles.active} 当通过配置文件来指定时必须放在 bootstrap.properties 文件中。 Nacos 上新增一个DataId为:nacos-config-develop.yaml的基础配置,如下所示: [source,subs="normal"] ---- Data ID: nacos-config-develop.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: current.env: develop-env ---- 启动 Spring Boot 应用测试的代码如下: [source,java] ---- @SpringBootApplication public class ConfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(ConfigApplication.class, args); while(true) { String userName = applicationContext.getEnvironment().getProperty("user.name"); String userAge = applicationContext.getEnvironment().getProperty("user.age"); //获取当前部署的环境 String currentEnv = applicationContext.getEnvironment().getProperty("current.env"); System.err.println("in "+currentEnv+" enviroment; "+"user name :" + userName + "; age: " + userAge); TimeUnit.SECONDS.sleep(1); } } } ---- 启动后,可见控制台的输出结果: [source,subs="normal"] ---- in develop-env enviroment; user name :nacos-config-yaml-update; age: 68 2018-11-02 15:34:25.013 INFO 33014 --- [ Thread-11] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6f1c29b7: startup date [Fri Nov 02 15:33:57 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@63355449 ---- 如果需要切换到生产环境,只需要更改 `${spring.profiles.active}` 参数配置即可。如下所示: [source,properties] ---- spring.profiles.active=product ---- 同时生产环境上 Nacos 需要添加对应 DataId 的基础配置。例如,在生成环境下的 Naocs 添加了DataId为:nacos-config-product.yaml的配置: [source,subs="normal"] ---- Data ID: nacos-config-product.yaml Group : DEFAULT_GROUP 配置格式: YAML 配置内容: current.env: product-env ---- 启动测试程序,输出结果如下: [source,subs="normal"] ---- in product-env enviroment; user name :nacos-config-yaml-update; age: 68 2018-11-02 15:42:14.628 INFO 33024 --- [Thread-11] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6aa8e115: startup date [Fri Nov 02 15:42:03 CST 2018]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@19bb07ed ---- NOTE: 此案例中我们通过 `spring.profiles.active=` 的方式写死在配置文件中,而在真正的项目实施过程中这个变量的值是需要不同环境而有不同的值。这个时候通常的做法是通过 `-Dspring.profiles.active=` 参数指定其配置来达到环境间灵活的切换。 === 支持自定义 namespace 的配置 Nacos 内部有 https://nacos.io/zh-cn/docs/concepts.html[Namespace 的概念]: [quote] 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 在没有明确指定 `${spring.cloud.nacos.config.namespace}` 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间,可以通过以下配置来实现: [source,properties] ---- spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7 ---- NOTE: 该配置必须放在 bootstrap.properties 文件中。此外 `spring.cloud.nacos.config.namespace` 的值是 namespace 对应的 id,id 值可以在 Nacos 的控制台获取。并且在添加配置时注意不要选择其他的 namespae,否则将会导致读取不到正确的配置。 === 支持自定义 Group 的配置 在没有明确指定 `${spring.cloud.nacos.config.group}` 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现: [source,properties] ---- spring.cloud.nacos.config.group=DEVELOP_GROUP ---- NOTE: 该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 `spring.cloud.nacos.config.group` 的配置值一致。 === 支持自定义扩展的 Data Id 配置 Nacos Config 从 0.2.1 版本后,可支持自定义 Data Id 的配置。关于这部分详细的设计可参考 https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/141[这里]。 一个完整的配置案例如下所示: [source,properties] ---- spring.application.name=opensource-service-provider spring.cloud.nacos.config.server-addr=127.0.0.1:8848 # config external configuration # 1、Data Id 在默认的组 DEFAULT_GROUP,不支持配置的动态刷新 spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties # 2、Data Id 不在默认的组,不支持动态刷新 spring.cloud.nacos.config.ext-config[1].data-id=ext-config-common02.properties spring.cloud.nacos.config.ext-config[1].group=GLOBALE_GROUP # 3、Data Id 既不在默认的组,也支持动态刷新 spring.cloud.nacos.config.ext-config[2].data-id=ext-config-common03.properties spring.cloud.nacos.config.ext-config[2].group=REFRESH_GROUP spring.cloud.nacos.config.ext-config[2].refresh=true ---- 可以看到: * 通过 `spring.cloud.nacos.config.ext-config[n].data-id` 的配置方式来支持多个 Data Id 的配置。 * 通过 `spring.cloud.nacos.config.ext-config[n].group` 的配置方式自定义 Data Id 所在的组,不明确配置的话,默认是 DEFAULT_GROUP。 * 通过 `spring.cloud.nacos.config.ext-config[n].refresh` 的配置方式来控制该 Data Id 在配置变更时,是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。 NOTE: 多个 Data Id 同时配置时,他的优先级关系是 `spring.cloud.nacos.config.ext-config[n].data-id` 其中 n 的值越大,优先级越高。 NOTE: `spring.cloud.nacos.config.ext-config[n].data-id` 的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml。 此时 `spring.cloud.nacos.config.file-extension` 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。 通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。 为了更加清晰的在多个应用间配置共享的 Data Id ,你可以通过以下的方式来配置: [source,properties] ---- spring.cloud.nacos.config.shared-dataids=bootstrap-common.properties,all-common.properties spring.cloud.nacos.config.refreshable-dataids=bootstrap-common.properties ---- 可以看到: * 通过 `spring.cloud.nacos.config.shared-dataids` 来支持多个共享 Data Id 的配置,多个之间用逗号隔开。 * 通过 `spring.cloud.nacos.config.refreshable-dataids` 来支持哪些共享配置的 Data Id 在配置变化时,应用中是否可动态刷新, 感知到最新的配置值,多个 Data Id 之间用逗号隔开。如果没有明确配置,默认情况下所有共享配置的 Data Id 都不支持动态刷新。 NOTE: 通过 `spring.cloud.nacos.config.shared-dataids` 来支持多个共享配置的 Data Id 时, 多个共享配置间的一个优先级的关系我们约定:按照配置出现的先后顺序,即后面的优先级要高于前面。 NOTE: 通过 `spring.cloud.nacos.config.shared-dataids` 来配置时,Data Id 必须带文件扩展名,文件扩展名既可支持 properties,也可以支持 yaml/yml。 此时 `spring.cloud.nacos.config.file-extension` 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。 NOTE: `spring.cloud.nacos.config.refreshable-dataids` 给出哪些需要支持动态刷新时,Data Id 的值也必须明确给出文件扩展名。 === 配置的优先级 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 === Nacos Config 对外暴露的 Endpoint Nacos Config 内部提供了一个 Endpoint, 对应的 endpoint id 为 `nacos-config`。 Endpoint 暴露的 json 中包含了两种属性: 1. Sources: 当前应用配置的数据信息 2. RefreshHistory: 配置刷新的历史记录 3. NacosConfigProperties: 当前应用 Nacos 的基础配置信息 这是 Endpoint 暴露的 json 示例: [source,json,indent=0] ---- { "NacosConfigProperties": { "serverAddr": "127.0.0.1:8848", "encode": null, "group": "DEFAULT_GROUP", "prefix": null, "fileExtension": "properties", "timeout": 3000, "endpoint": null, "namespace": null, "accessKey": null, "secretKey": null, "contextPath": null, "clusterName": null, "name": null, "sharedDataids": "base-common.properties,common.properties", "refreshableDataids": "common.properties", "extConfig": null }, "RefreshHistory": [{ "timestamp": "2019-07-29 11:20:04", "dataId": "nacos-config-example.properties", "md5": "7d5d7f1051ff6571e2ec9f90887d9d91" }], "Sources": [{ "lastSynced": "2019-07-29 11:19:04", "dataId": "common.properties" }, { "lastSynced": "2019-07-29 11:19:04", "dataId": "base-common.properties" }, { "lastSynced": "2019-07-29 11:19:04", "dataId": "nacos-config-example.properties" }] } ---- === 完全关闭 Nacos Config 的自动化配置 通过设置 spring.cloud.nacos.config.enabled = false 来完全关闭 Spring Cloud Nacos Config === 关于 Nacos Config Starter 更多的配置项信息 更多关于 Nacos Config Starter 的配置项如下所示: :frame: topbot [width="60%",options="header"] |==== ^|配置项 ^|Key ^|默认值 ^|说明 |服务端地址|`spring.cloud.nacos.config.server-addr`|| Nacos Server 启动监听的ip地址和端口 |配置对应的 DataId|`spring.cloud.nacos.config.name`|| 先取 prefix,再去 name,最后取 spring.application.name |配置对应的 DataId|`spring.cloud.nacos.config.prefix`|| 先取 prefix,再去 name,最后取 spring.application.name |配置内容编码|`spring.cloud.nacos.config.encode`||读取的配置内容对应的编码 |GROUP|`spring.cloud.nacos.config.group`|`DEFAULT_GROUP`|配置对应的组 |文件扩展名|`spring.cloud.nacos.config.fileExtension`|`properties`|配置项对应的文件扩展名,目前支持 properties 和 yaml(yml) |获取配置超时时间|`spring.cloud.nacos.config.timeout`|`3000`|客户端获取配置的超时时间(毫秒) |接入点|`spring.cloud.nacos.config.endpoint`||地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 |命名空间|`spring.cloud.nacos.config.namespace`||常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等 |AccessKey|`spring.cloud.nacos.config.accessKey`||当要上阿里云时,阿里云上面的一个云账号名 |SecretKey|`spring.cloud.nacos.config.secretKey`||当要上阿里云时,阿里云上面的一个云账号密码 |Nacos Server 对应的 context path|`spring.cloud.nacos.config.contextPath`||Nacos Server 对外暴露的 context path |集群|`spring.cloud.nacos.config.clusterName`||配置成Nacos集群名称 |共享配置|`spring.cloud.nacos.config.sharedDataids`||共享配置的 DataId, "," 分割 |共享配置动态刷新|`spring.cloud.nacos.config.refreshableDataids`||共享配置中需要动态刷新的 DataId, "," 分割 |自定义 Data Id 配置|`spring.cloud.nacos.config.extConfig`||属性是个集合,内部由 `Config` POJO 组成。`Config` 有 3 个属性,分别是 `dataId`, `group` 以及 `refresh` |====