== Spring Cloud Alibaba Nacos Discovery

This project provides seamless integration with Nacos for Spring Boot applications in terms of service registration and discovery through automatic configurations and other standard usages of the Spring programming model.
Nacos has endured the tough tests of the Double 11 Shopping festivals for years. By adding a few simple annotations, you can register a service quickly and use Nacos as the service registration center for a large scale distributed system.

=== Service Registration and Discovery: Nacos Discovery Starter

Service discovery is one of the key components in the microservices architecture. In such a architecture, configuring a service list for every client manually could be a daunting task, and makes dynamic scaling extremely difficult.
 Nacos Discovery Starter helps you to register your service to the Nacos server automatically, and the Nacos server keeps track of the services and refreshes the service list dynamically. In addition, Nacos
Discovery Starter registers some of the metadata of the service instance, such as host, port, health check URL, homepage to Nacos. For details about how to download and start Nacos, refer to the https://nacos.io/zh-cn/docs/quick-start.html[Nacos Website]。

==== How to Introduce Nacos Discovery Starter

please use the starter with the group ID as `org.springframework.cloud` and the artifact ID as `spring-cloud-starter-alibaba-nacos-discovery`.

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

==== Start a Provider Application

The following sample illustrates how to register a service to Nacos.

1. Configuration of pom.xml The following is a complete example of pom.xml:
[source, 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>open.source.test</groupId>
    <artifactId>nacos-discovery-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>nacos-discovery-test</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>${spring.boot.version}</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.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>
            </plugin>
        </plugins>
    </build>
</project>
----

2. Configuration of application.properties Some of the basic configurations of Nacos must be included in application.properties(or application.yaml), as shown below：
application.properties
[source,properties]
----
server.port=8081
spring.application.name=nacos-producer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*
----


NOTE: If you do not want to use Nacos for service registration and discovery, you can set `spring.cloud.nacos.discovery` to `false`.

3. The following is a sample for starting Provider:
[source,java,indent=0]
----
@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProducerDemoApplication.class, args);
    }

    @RestController
    public class EchoController {
        @GetMapping(value = "/echo/{string}")
        public String echo(@PathVariable String string) {
            return "Hello Nacos Discovery " + string;
        }
    }
}
----

Now you can see the registered services on the Nacos console.

NOTE: Before you start the provider application, please start Nacos first. Refer to https://nacos.io/zh-cn/docs/quick-start.html[Naco Website] for more details.

=== Service EndPoint

spring-cloud-starter-alibaba-nacos-discovery provides an EndPoint, and the address is `http://ip:port/actuator/nacos-discovery`.
The EndPoint mainly provides two types of information:

    1. Subscribe: Shows the current service subscribers
    2. NacosDiscoveryProperties: Shows the current basic Nacos configurations of the current service

The followings shows how a service instance accesses the EndPoint:

[source, json]
----
{
  "subscribe": [
    {
      "jsonFromServer": "",
      "name": "nacos-provider",
      "clusters": "",
      "cacheMillis": 10000,
      "hosts": [
        {
          "instanceId": "30.5.124.156#8081#DEFAULT#nacos-provider",
          "ip": "30.5.124.156",
          "port": 8081,
          "weight": 1.0,
          "healthy": true,
          "enabled": true,
          "cluster": {
            "serviceName": null,
            "name": null,
            "healthChecker": {
              "type": "TCP"
            },
            "defaultPort": 80,
            "defaultCheckPort": 80,
            "useIPPort4Check": true,
            "metadata": {

            }
          },
          "service": null,
          "metadata": {

          }
        }
      ],
      "lastRefTime": 1541755293119,
      "checksum": "e5a699c9201f5328241c178e804657e11541755293119",
      "allIPs": false,
      "key": "nacos-producer",
      "valid": true
    }
  ],
  "NacosDiscoveryProperties": {
    "serverAddr": "127.0.0.1:8848",
    "endpoint": "",
    "namespace": "",
    "logName": "",
    "service": "nacos-provider",
    "weight": 1.0,
    "clusterName": "DEFAULT",
    "metadata": {

    },
    "registerEnabled": true,
    "ip": "30.5.124.201",
    "networkInterface": "",
    "port": 8082,
    "secure": false,
    "accessKey": "",
    "secretKey": ""
  }
}
----

=== Start a Consumer Application

It might not be as easy as starting a provider application, because the consumer needs to call the RESTful service of the provider. In this example, we will use the most primitive way, that is,
combining the LoadBalanceClient and RestTemolate explicitly to access the RESTful service.
You can refer to section 1.2 for pom.xml and application.properties configurations. The following is the sample code for starting a consumer application.

NOTE: You can also access the service by using RestTemplate and FeignClient with load balancing.

[source, java]
----
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApp {

    @RestController
    public class NacosController{

        @Autowired
        private LoadBalancerClient loadBalancerClient;
        @Autowired
        private RestTemplate restTemplate;

        @Value("${spring.application.name}")
        private String appName;

        @GetMapping("/echo/app-name")
        public String echoAppName(){
            //Access through the combination of LoadBalanceClient and RestTemolate
            ServiceInstance serviceInstance = loadBalancerClient.choose("nacos-provider");
            String path = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),appName);
            System.out.println("request path:" +path);
            return restTemplate.getForObject(path,String.class);
        }

    }

    //Instantiate RestTemplate Instance
    @Bean
    public RestTemplate restTemplate(){

        return new RestTemplate();
    }

    public static void main(String[] args) {

        SpringApplication.run(NacosConsumerApp.class,args);
    }
}
----

In this example, we injected a LoadBalancerClient instance, and instantiated a RestTemplate manually. At the same time, we injected the configuration value of `spring.application.name` into the application,
so that the current application name can be displayed when calling the service of the provider.

NOTE: Please start Nacos before you start the consumer application. For details, please refer to https://nacos.io/zh-cn/docs/quick-start.html[Nacos Website].

Next, access the `http://ip:port/echo/app-name` interface provided by the consumer. Here we started the port of 8082. The access result is shown below：

 Address：http://127.0.0.1:8082/echo/app-name
 Access result： Hello Nacos Discovery nacos-consumer

=== More Information about Nacos Starter Configurations

The following shows the other configurations of the starter of spring-cloud-starter-alibaba-nacos-discovery:

:frame: topbot
[width="60%",options="header"]
|====
^|Configuration ^|Key ^|Default Value ^|Description
|`Server address`|`spring.cloud.nacos.discovery.server-addr`|`No default value`|`IP and port of the Nacos Server listener`
|`Service name`|`spring.cloud.nacos.discovery.service`|`${spring.application.name}`|`Name the current service`
|`Weight`|`spring.cloud.nacos.discovery.weight`|`1`|`Value range: 1 to 100. The bigger the value, the greater the weight`
|`Network card name`|`spring.cloud.nacos.discovery.network-interface`|`No default value`|`If the IP address is not specified, the registered IP address is the IP address of the network card. If this is not specified either, the IP address of the first network card will be used by default.`
|`Registered IP address`|`spring.cloud.nacos.discovery.ip`|`No default value`|`Highest priority`
|`Registered port`|`spring.cloud.nacos.discovery.port`|`-1`|`Will be detected automatically by default. Do not need to be configured.`
|`Namespace`|`spring.cloud.nacos.discovery.namespace`|`No default value`|`A typical scenario is to isolate the service registration for different environment, such as resource (configurations, services etc.) isolation between testing and production environment` `
|`AccessKey`|`spring.cloud.nacos.discovery.access-key`|`No default value`|`Alibaba Cloud account`
|`SecretKey`|`spring.cloud.nacos.discovery.secret-key`|`No default value`|`Alibaba Cloud account accesskey`
|`Metadata`|`spring.cloud.nacos.discovery.metadata`|`No default value`|`You can define some of the metadata for your services in the Map format`
|`Log file name`|`spring.cloud.nacos.discovery.log-name`|`No default value`|
|`Endpoint`|`spring.cloud.nacos.discovery.enpoint`|`UTF-8`|`The domain name of a certain service in a specific region. You can retrieve the server address dynamically with this domain name`
|`Integrate Ribbon or not`|`ribbon.nacos.enabled`|`true`|`Set to true in most cases`
|====

