== Spring Cloud Alibaba Nacos Config

Nacos is an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.

Use Spring Cloud Alibaba Nacos Config to quickly access Nacos configuration management capabilities based on Spring Cloud's programming model.

=== How to Introduce Nacos Config for configuration

please use the starter with the group ID as `com.alibaba.cloud` and the artifact ID as `spring-cloud-starter-alibaba-nacos-config`.

[source,xml,indent=0]
----
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
----

=== Quickstart

Nacos Config uses DataId and GROUP to determine a configuration.

The following figure shows that the DataId uses `myDataid`, GROUP uses `DEFAULT_GROUP`, and configures a configuration item of the format Properties:

.Nacos Config Item
image::https://img.alicdn.com/tfs/TB1N2nxbRr0gK0jSZFnXXbRRXXa-2448-1194.png[]

==== Initialize Nacos Server

For specific startup methods, refer to the "Nacos Server Startup" section of the Spring Cloud Alibaba Nacos Discovery section.

After the Nacos Server is started, add how to configure it:

[source,subs="normal"]
----
Data ID:    nacos-config.properties

Group  :    DEFAULT_GROUP

Configuration format:    Properties

Configuration content:   user.name=nacos-config-properties
            user.age=90
----

NOTE: The default file extension of DataId is properties.

===== Usage on the Client

If you want to use Nacos to manage externalized configurations for your applications, please use the starter with the group ID as `com.alibaba.cloud` and the artifact ID as `spring-cloud-starter-alibaba-nacos-config`.

[source,xml]
----
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
----

Now we can create a standard Spring Boot application.

[source,java]
----
@SpringBootApplication
public class NacosConfigApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigApplication.class, args);
        String userName = applicationContext.getEnvironment().getProperty("user.name");
        String userAge = applicationContext.getEnvironment().getProperty("user.age");
        System.err.println("user name :" +userName+"; age: "+userAge);
    }
}
----

Before running this example, we need to configure the address of the Nacos server in bootstrap.properties. For example:

.bootstrap.properties
[source,properties]
----
# DataId By default, the `spring.application.name` configuration is combined with the file extension (the configuration format uses properties by default), and the GROUP is not configured to use DEFAULT_GROUP by default. Therefore, the Nacos Config configuration corresponding to the configuration file has a DataId of nacos-config.properties and a GROUP of DEFAULT_GROUP
spring.application.name=nacos-config
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
----

NOTE: If you use domain name to access Nacos, the format of `spring.cloud.nacos.config.server-addr` should be `Domain name:port`.
For example, if the Nacos domain name is abc.com.nacos, and the listerner port is 80, then the configuration should be `spring.cloud.nacos.config.server-addr=abc.com.nacos:80`.
Port 80 cannot be omitted.

Run this example and you can see the following output:

[source,subs="normal"]
----
2018-11-02 14:24:51.638  INFO 32700 --- [main] c.a.demo.provider.NacosConfigApplication    : Started NacosConfigApplication 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
----

=== Add Configurations with DataId in YAML Format

Nacos Config supports yaml format as well. You only need to complete the following 2 steps.

1. In the bootstrap.properties file, add the following line to claim that the format of DataId is yaml. As follows:

.bootstrap.properties
[source,yaml]
----
spring.cloud.nacos.config.file-extension=yaml
----

2. Add a configuration with the DataId in yaml format on the Nacos console, as shown below:

[source,subs="normal"]
----
Data ID:        nacos-config.yaml

Group  :        DEFAULT_GROUP

Configuration format:        YAML

Configuration content:        user.name: nacos-config-yaml
                              user.age: 68
----

After completing the preivous two steps, restart the testing program and you will see the following result.

[source,subs="normal"]
----
2018-11-02 14:59:00.484  INFO 32928 --- [main] c.a.demo.provider.NacosConfigApplication:Started NacosConfigApplication 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
----

=== Support Dynamic Configuration Udpates

Nacos Config also supports dynamic configuration updates. The code for starting Spring Boot application testing is as follows:

[source,java]
----
@SpringBootApplication
public class NacosConfigApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigApplication.class, args);
        while(true) {
            //When configurations are refreshed dynamically, they will be updated in the Enviroment, therefore here we retrieve configurations from Environment every other second.
            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);
        }
    }
}
----

When user.name is changed, the latest value can be retrieved from the application, as shown below:

[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
//Read the updated value from Enviroment
user name :nacos-config-yaml-update; age: 68
user name :nacos-config-yaml-update; age: 68
----

NOTE: You can disable automatic refresh with this setting`spring.cloud.nacos.config.refresh.enabled=false`.

=== Support configurations at the profile level

When configurations are loaded by Nacos Config, basic configurations with  DataId of `${spring.application.name}. ${file-extension:properties}` , and DataId of `${spring.application.name}-${profile}. ${file-extension:properties}` are also loaded. If you need to use different configurations from different environments, you can use the `${spring.profiles.active}` configuration provided by Spring.

[source,properties]
----
spring.profiles.active=develop
----

NOTE: When specified in configuration files, ${spring.profiles.active} must be placed in bootstrap.properties.

Add a basic configuration in Nacos, with a DataId of nacos-config-develop.yaml, as shown below:

[source,subs="normal"]
----
Data ID:        nacos-config-develop.yaml

Group  :        DEFAULT_GROUP

Configuration format:        YAML

Configuration content:        current.env: develop-env
----

Run the following Spring Boot application testing code:

[source,java]
----
@SpringBootApplication
public class NacosConfigApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(NacosConfigApplication.class, args);
        while(true) {
            String userName = applicationContext.getEnvironment().getProperty("user.name");
            String userAge = applicationContext.getEnvironment().getProperty("user.age");
            //Get the current deployment environment
            String currentEnv = applicationContext.getEnvironment().getProperty("current.env");
            System.err.println("in "+currentEnv+" enviroment; "+"user name :" + userName + "; age: " + userAge);
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
----
After started, you can see the output as follows in the console:

[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
----

To switch to the production environment, you only need to change the parameter of `${spring.profiles.active}`. As show below:

[source,properties]
----
spring.profiles.active=product
----

At the same time, add the basic configuration with the DataId in the  Nacos of your production environment. For example, you can add the configuration with the DataId of nacos-config-product.yaml in Nacos of your production environment:

[source,subs="normal"]
----
Data ID:        nacos-config-product.yaml

Group  :        DEFAULT_GROUP

Configuration format:        YAML

Configuration content:        current.env: product-env
----

Start the testing program and you will see the following result:

[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: In this example, we coded the configuration in the configuration file by using the `spring.profiles.active=<profilename>` method. In real scenarios, this variable needs to be different in different environment. You can use the `-Dspring.profiles.active=<profile>` parameter to specify the configuration so that you can switch between different environments easily.

=== Support Custom Namespaces
For details about namespaces in Nacos, refer to https://nacos.io/zh-cn/docs/concepts.html[Nacos Concepts]

[quote]
Namespaces are used to isolate configurations for different tenants. Groups and Data IDs can be the same across different namespaces. Typical scenarios of namespaces is the isolation of configurations for different environments, for example, isolation between development/testing environments and production environments(configurations and services and so on).

The “Public” namespace of Nacos is used if no namespace is specified in `${spring.cloud.nacos.config.namespace}`. You can also specify a custom namespace in the following way：
[source,properties]
----
spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7
----

NOTE: This configuration must be in the bootstrap.properties file. The value of `spring.cloud.nacos.config.namespace` is the id of the namespace, and the value of id can be retrieved from the Nacos console. Do not select other namespaces when adding configurations. Otherwise configurations cannot be retrieved properly.

=== Support Custom Groups

DEFAULT_GROUP is used by default when no `{spring.cloud.nacos.config.group}` configuration is defined. If you need to define your own group, you can define it in the following property:

[source,properties]
----
spring.cloud.nacos.config.group=DEVELOP_GROUP
----

NOTE: This configuration must be in the bootstrap.properties file, and the value of Group must be the same with the value of `spring.cloud.nacos.config.group`.

=== Support Custom Data Id

As of Spring Cloud Alibaba Nacos Config, data id can be self-defined. For detailed design of this part, refer to https://github.com/spring-cloud-incubator/spring-cloud-alibaba/issues/141[Github issue].
The following is a complete sample:

[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 is in the default group of DEFAULT_GROUP, and dynamic refresh of configurations is not supported.
spring.cloud.nacos.config.ext-config[0].data-id=ext-config-common01.properties

# 2. Data Id is not in the default group, and dynamic refresh of configurations is not supported.
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 is not in the default group and dynamic referesh of configurations is supported.
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
----

We can see that:

* Support multiple data ids by configuring `spring.cloud.nacos.config.ext-config[n].data-id`.
* Customize the group of data id by configuring `spring.cloud.nacos.config.ext-config[n].group`. If not specified,  DEFAULT_GROUP is used.
* Control whether this data id supports dynamic refresh of configurations is supported when configurations are changed by configuring `spring.cloud.nacos.config.ext-config[n].refresh`.
 It’s not supported by default.


NOTE: When multiple Data Ids are configured at the same time, the priority is defined by the value of “n” in `spring.cloud.nacos.config.ext-config[n].data-id`. The bigger the value, the higher the priority.

NOTE: The value of `spring.cloud.nacos.config.ext-config[n].data-id` must have a file extension, and it could be properties or yaml/yml.
The setting in `spring.cloud.nacos.config.file-extension` does not have any impact on the custom Data Id file extension.

The configuration of custom Data Id allows the sharing of configurations among multiple applications, and also enables support of multiple configurations for one application.

To share the data id among multiple applications in a clearer manner, you can also use the following method:

[source,properties]
----
spring.cloud.nacos.config.shared-dataids=bootstrap-common.properties,all-common.properties
spring.cloud.nacos.config.refreshable-dataids=bootstrap-common.properties
----

We can see that:

* Multiple shared data ids can be configured using `spring.cloud.nacos.config.shared-dataids` , and the data ids are separted by commas.
* `spring.cloud.nacos.config.refreshable-dataids` is used to control which data ids will be refreshed dynamically when configurations are updated, and that the latest configuration values can be retrieved by applications. Data ids are separated with commas.
 If not specified, all shared data ids will not be dynamically refreshed.

NOTE: When using `spring.cloud.nacos.config.shared-dataids` to configure multiple shared data ids,
we agree on the following priority between the shared configurations: Priorities are decided based on the order in which the configurations appear. The one that occurs later is higher in priority than the one that appears first.

NOTE: When using `spring.cloud.nacos.config.shared-dataids`, the data Id must have a file extension, and it could be properties or yaml/yml.
And the configuration in `spring.cloud.nacos.config.file-extension` does not have any impact on the customized Data Id file extension.

NOTE: When `spring.cloud.nacos.config.refreshable-dataids` specifies the data ids that support dynamic refresh, the corresponding values of the data ids should also specify file extensions.

=== Nacos Config Endpoint

Nacos Config provides an Endpoint internally with a corresponding endpoint id of `nacos-config`.

Endpoint exposed json contains three properties:

1. Sources: Current application configuration data information

2. RefreshHistory: Configuration refresh history

3. NacosConfigProperties: Shows the current basic Nacos configurations of the current service

The followings shows how a service instance accesses the Endpoint:

[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"
	}]
}
----


=== Disable Nacos Config AutoConfiguration

set spring.cloud.nacos.config.enabled = false to disable Spring Cloud Nacos Config AutoConfiguration.

=== More Information about Nacos Config Starter Configurations

The following shows the other configurations of the starter of Nacos Config:

:frame: topbot
[width="60%",options="header"]
|====
^|Configuration ^|Key ^|Default Value ^|Description
|Server address|`spring.cloud.nacos.config.server-addr`|| IP and port of the Nacos Server listener
|Dataid from nacos config|`spring.cloud.nacos.config.name`|| First take the prefix, then go to the name, and finally take spring.application.name
|Dataid from nacos config|`spring.cloud.nacos.config.prefix`|| First take the prefix, then go to the name, and finally take spring.application.name
|Encode for nacos config content|`spring.cloud.nacos.config.encode`||Encode for nacos config content
|GROUP for nacos config|`spring.cloud.nacos.config.group`|`DEFAULT_GROUP`|GROUP for nacos config
|The suffix of nacos config dataId, also the file extension of config content.|`spring.cloud.nacos.config.fileExtension`|`properties`|The suffix of nacos config dataId, also the file extension of config content(now support properties or yaml(yml))
|Timeout for get config from nacos|`spring.cloud.nacos.config.timeout`|`3000`|Timeout for get config from nacos
|Endpoint|`spring.cloud.nacos.config.endpoint`||Endpoint
|Namespace|`spring.cloud.nacos.config.namespace`||Namespace
|AccessKey|`spring.cloud.nacos.config.accessKey`||Alibaba Cloud account accesskey
|SecretKey|`spring.cloud.nacos.config.secretKey`||Alibaba Cloud account secretkey
|The context path of Nacos Server|`spring.cloud.nacos.config.contextPath`||The context path of Nacos Server
|Cluster name|`spring.cloud.nacos.config.clusterName`||Cluster name
|Dataid for Shared Configuration|`spring.cloud.nacos.config.sharedDataids`||Dataid for Shared Configuration, split by ","
|Dynamic refresh dataid for Shared Configuration|`spring.cloud.nacos.config.refreshableDataids`||Dynamic refresh dataid for Shared Configuration, split by ","
|custom dataid|`spring.cloud.nacos.config.extConfig`||It's a List，build up by `Config` POJO. `Config` has 3 attributes, `dataId`, `group` and `refresh`
|====