Alibaba Nacos registry of Spring Cloud series

preface

  

From the beginning of this chapter, we learn about Spring Cloud Alibaba related micro service components.

Introduction to Spring Cloud Alibaba

  

Spring Cloud Alibaba is committed to providing a one-stop solution for microservice development. This project contains the necessary components for developing distributed application microservices, which is convenient for developers to develop distributed application services through Spring Cloud programming model.

Relying on Spring Cloud Alibaba, you can connect Spring Cloud applications to Alibaba microservice solutions by adding some annotations and a few configurations, and quickly build distributed application systems through Alibaba middleware.

  

Spring Cloud Alibaba features

  

  1. Sentinel: it supports the access of WebServlet, WebFlux, OpenFeign, RestTemplate, Dubbo, Gateway and Zuul current limiting degradation functions. The current limit degradation rules can be modified in real time through the console at runtime, and the current limit degradation metric monitoring is also supported.
  2. Service registration and discovery Nacos: it adapts to the Spring Cloud service registration and discovery standard, and integrates the support of Ribbon by default.
  3. Distributed configuration management Nacos: supports the external configuration in the distributed system, and refreshes automatically when the configuration changes.
  4. RPC service Dubbo: extend Spring Cloud client RestTemplate and OpenFeign to support calling Dubbo RPC service.
  5. Message driven RocketMQ: build message driven capabilities for microservice applications based on Spring Cloud Stream.
  6. Distributed transaction Seata: supports high performance and easy to use distributed transaction solutions.
  7. Alibaba cloud object storage OSS: a large-scale, secure, low-cost, highly reliable cloud storage service. Support to store and access any type of data in any application anytime, anywhere.
  8. Distributed task scheduling SchedulerX: provides second level, accurate, highly reliable and highly available scheduled (based on Cron expression) task scheduling services. At the same time, it provides distributed task execution model, such as grid task. Grid tasks support the sea quantum tasks to be evenly distributed to all workers (SchedulerX client).
  9. Alibaba cloud SMS service: a global SMS service with friendly, efficient and intelligent communication capabilities, helps enterprises quickly build customer access channels.

  

Spring Cloud Alibaba component

  

  • Nacos: Alibaba open source product, a dynamic service discovery, configuration management and service management platform that is easier to build cloud native applications.
  • Sentinel: a lightweight traffic control product for distributed service architecture, which takes traffic as the entry point to protect the stability of services from multiple dimensions such as traffic control, fuse degradation, system load protection, etc.
  • RocketMQ: an open-source distributed message system, based on the highly available distributed cluster technology, provides low latency and highly reliable message publishing and subscription services.
  • Dubbo: Apache Dubbo ™ Is a high-performance Java RPC framework.
  • Seata: Alibaba open source product, an easy-to-use high-performance micro service distributed transaction solution.
  • Alibaba Cloud ACM: an application configuration center product that centrally manages and pushes application configurations in a distributed architecture environment.
  • Alibaba Cloud OSS: Alibaba cloud Object Storage Service (OSS) is a massive, secure, low-cost, and highly reliable cloud storage service provided by Alibaba cloud. You can store and access any type of data in any application, at any time, anywhere.
  • Alibaba Cloud SchedulerX: a distributed task scheduling product developed by Alibaba middleware team, which provides second level, accurate, highly reliable and highly available scheduled (based on Cron expression) task scheduling services.
  • Alibaba Cloud SMS: covering the world's SMS services, friendly, efficient and intelligent Internet communication capabilities help enterprises quickly build customer access channels.

  

What is a registry

  

Service registry is the core component of service management, which is similar to directory service. It is mainly used to store service information, such as provider url string, routing information, etc. Service registry is one of the most basic facilities in microservice architecture.

The registry can be called the "address book" in the microservice architecture, which records the mapping relationship between the service and the service address. In the distributed architecture, the service will register here. When the service needs to call other services, it will find the address of the service and call.

The simple understanding is: when there is no registry, the inter service call needs to know the specific address of the service caller (written dead ip:port). When you change the deployment address, you have to change the address specified in the call. With the registration center, each service only needs to know the service name (soft code) when calling others. The address will be called by the registration center according to the specific service address obtained by the service name.

Take an example in real life. For example, there are two usage scenarios of the address book in our mobile phone:

When I want to call Zhang San, I need to find Zhang San by name in the address book, and then I can find his mobile number to make a call. ——Service discovery

Li Si has a mobile number and told me the mobile number. I put Li Si's number in the address book. Later, I can find him from the address book. ——Service registration

Address book -? What role (service registry)

Conclusion: the function of service registry is to register and discover services.

  

Common registries

  

  • Netflix Eureka
  • Alibaba Nacos
  • HashiCorp Consul
  • Apache ZooKeeper
  • CoreOS Etcd
  • CNCF CoreDNS

  

characteristic Eureka Nacos Consul Zookeeper
CAP AP CP + AP CP CP
health examination Client Beat TCP/HTTP/MYSQL/Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
Avalanche protection Yes Yes nothing nothing
Auto logout instance support support I won't support it support
access protocol HTTP HTTP/DNS HTTP/DNS TCP
Monitoring support support support support support
Multi data center support support support I won't support it
Synchronization across registries I won't support it support support I won't support it
Spring cloud integration support support support support

  

CAP principle and BASE theory

  

CAP principles

  

  

CAP principle, also known as CAP theorem, refers to that in a distributed system, Consistency, Availability and Partition tolerance cannot be obtained simultaneously.

CAP was proposed by Eric Brewer at the 2000 PODC conference. This conjecture was proved to be true two years after it was put forward, and became the CAP theorem we are familiar with. CAP is not a combination of the three.

characteristic theorem
Consistency Also known as data atomicity, the system is still in a consistent state after performing an operation. In a distributed system, all users should read the latest value after the update operation is performed successfully. Such a system is considered to have strong consistency. Equivalent to all nodes accessing the same copy of the latest data.
Availability Every operation can always return results within a certain period of time. Here, we need to pay attention to "within a certain period of time" and "return results". Within a certain period of time, it means that the result can be returned within a tolerable range. The result can be success or failure.
Partition tolerance In the case of network partition, the separated nodes can still provide external services normally (distributed cluster, data is stored on different servers, no matter what, the servers can be accessed normally).

  

Trade-off strategy

  

The three characteristics of CAP can only satisfy two of them, so there are three strategies for choosing:

  • CA without P: if P is not required (partition is not allowed), then C (strong consistency) and A (availability) can be guaranteed. But to give up P means to give up the expansibility of the system, that is to say, the distributed nodes are limited and there is no way to deploy the sub nodes, which is against the original intention of the distributed system design.
  • CP without A: If a (available) is not required, it means that each request needs to keep strong consistency between servers, and P (partition) will lead to unlimited extension of synchronization time (that is, waiting for data synchronization to complete before normal access to services). Once network failure or message loss occurs, the user's experience will be sacrificed, and the user will be allowed to wait for all data to be consistent Access the system. There are many systems designed as CP, the most typical of which are distributed databases, such as Redis, HBase, etc. For these distributed databases, data consistency is the most basic requirement, because if this standard can not be met, it is better to use relational database directly, and there is no need to waste resources to deploy distributed database.
  • AP without C: to be highly available and allow partitioning, you need to discard consistency. Once the partition occurs, the nodes may lose contact with each other. In order to be highly available, each node can only provide services with local data, which will lead to global data inconsistency. A typical application is like the scene of a certain meter's mobile phone. Maybe when you browse the goods a few seconds ago, the page prompts that there is inventory. When you choose the goods and are ready to place an order, the system prompts you that the order fails and the goods are sold out. This is to ensure that the system can provide normal services in a (availability) first, and then make some sacrifices in data consistency. Although it will affect some user experience, it will not cause serious blocking of user shopping process.

  

summary

  

Nowadays, for most large-scale Internet application scenarios, there are many hosts, scattered deployment, and now the scale of the cluster is getting larger and larger, only more and more nodes, so node failure and network failure are normal, so partition fault tolerance has become an inevitable problem for A distributed system. Then we can only choose between C and A. However, the traditional project may be different. For the bank's transfer system, the money involved cannot make A little concession to the data consistency. C must ensure that in case of network failure, it is better to stop the service and make A choice between A and P.

In a word, there is no best strategy. A good system should be designed according to the business scenario, and only the appropriate one is the best.

  

BASE theory

  

CAP theory has been put forward for many years. Is there really no way to solve this problem? Maybe we can make some changes. For example, C does not need to use such strong consistency. It can store the data first, and then update it later to achieve the so-called "final consistency".

This idea is a huge problem, but also leads to the second theory BASE theory.

BASE: abbreviation of three phrases: basic available, Soft state and finally consistent. It is proposed by the architect of ebay.

BASE theory is the result of trade-off between consistency and availability in CAP, which is derived from the summary of large-scale Internet distributed practice, and is based on the gradual evolution of CAP theorem. Its core idea is:

Since Strong consistency cannot be achieved, each application can adopt appropriate ways to achieve the final consistency according to its own business characteristics.

  

Basically Available

  

Basic availability refers to that when the distributed system fails, it is allowed to lose part of the availability (such as response time, functional availability). It should be noted that basic availability is never equivalent to system unavailability.

  • Loss of response time: under normal circumstances, search engines need to return the corresponding query results to users within 0.5 seconds, but the response time of query results increases to 1-2 seconds due to failure (such as power failure or network outage failure in some machine rooms of the system).
  • Functional loss: in order to protect the stability of the system, some consumers may be guided to a degraded page during the shopping peak (such as the double 11).

  

Soft state

  

What is soft state? Compared with atomicity, the data copies of multiple nodes are required to be consistent, which is a "hard state".

Soft state means that the system is allowed to have an intermediate state, which will not affect the overall availability of the system. In distributed storage, there are usually multiple copies of a data. The delay to allow different copies of data to synchronize is the embodiment of soft state.

  

Eventually consistent

  

It is impossible for the system to be soft all the time. There must be a time limit. At the end of the period, data consistency should be ensured for all copies. So as to achieve the final consistency of data. This time limit depends on network delay, system load, data replication scheme design and other factors.

In fact, it is not only the final consistency used by the distributed system, but also the final consistency used by the relational database in a certain function. For example, it takes time for the database to be copied. In the process of copying, the value read by the business is the old value. Of course, data consistency was finally achieved. This is also a classic case of ultimate consistency.

  

summary

  

Generally speaking, the BASE theory is for a large-scale, highly available and scalable distributed system. It is the opposite of the ACID of traditional transactions. It is totally different from the strong consistency model of ACID, but it obtains the availability by sacrificing the strong consistency, and allows the data to be inconsistent for a period of time.

  

Why do I need a registry

  

Now that we know what a registry is, let's continue to talk about why a registry is needed. In the distributed system, we need not only to find the mapping relationship between services and service addresses in the registry, but also to consider more and more complex issues:

  • How to find out in time after service registration
  • How to get offline in time after service downtime
  • How to effectively expand the service level
  • How to route service discovery
  • How to downgrade when the service is abnormal
  • How to realize high availability of registry

The resolution of these problems depends on the registry. In short, the function of registry is similar to that of DNS server or load balancer. In fact, as the basic component of microservice, registry may be more complex and need more flexibility and timeliness. So we also need to learn more Spring Cloud micro service components to complete application development in collaboration.

  

The registry addresses the following issues:

  • Service management
  • Automatic discovery between services
  • Dependency management of services

  

Introduction to Nacos

  

Nacos is an open source tool launched by Alibaba company, which is used to realize service discovery and Configuration management of distributed system. The English full name is Dynamic Naming and Configuration Service. Na is Naming/NameServer, which is the registration center. co is Configuration, which is the Configuration center. Service means that the registration / Configuration center is based on services. Service is a first-class citizen of the Nacos world.

The official website says that it is easier to build a dynamic service discovery, configuration management and service management platform for cloud native applications.

Nacos is committed to discovering, configuring, and managing microservices. Nacos provides a set of simple and easy-to-use feature sets, which can quickly realize dynamic service discovery, service configuration, service metadata and traffic management.

Nacos can build, deliver, and manage microservice platforms more quickly and easily. Nacos is a service infrastructure for building a modern application architecture centered on "service".

Using Nacos to simplify service discovery, configuration management, service governance and management solutions makes the discovery, management, sharing and composition of microservices easier.

  

Nacos installation

  

Environmental preparation

  

Nacos relies on the Java environment to run. If you are building and running Nacos from code, you also need to configure the Maven environment for this, make sure you install and use it in the following version environment:

  • JDK 1.8+;
  • Maven 3.2.x+.

  

Download source code or installation package

  

Nacos can be obtained through source code and distribution package.

  

Source mode

  

Download the source code from Github.

git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

  

Distribution package method

  

You can https://github.com/alibaba/nacos/releases Download the latest stable version of the Nacos Server package.

  

Start server

  

Linux/Unix/Mac

  

Start in the directory nacos/bin of Nacos.

Start command (standalone stands for stand-alone mode operation, non cluster mode):

sh startup.sh -m standalone

If you are using the ubuntu system, or the error prompt of the running script cannot be found, you can try to run it as follows:

bash startup.sh -m standalone

  

Windows

  

Start command:

cmd startup.cmd

Or double click startup.cmd Run the file.

  

visit

  

Visit: http://localhost:8848/nacos/ , the default username / password is nacos/nacos.

  

Shut down the server

  

Linux/Unix/Mac

  

sh shutdown.sh

  

Windows

  

cmd shutdown.cmd

Or double click shutdown.cmd Run the file.

  

Nacos entry case

  

Create project

  

Let's create an aggregation project to explain Nacos. First, create a pom parent project.

  

Add dependency

  

  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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- Project coordinate address -->
    <groupId>com.example</groupId>
    <!-- Project module name -->
    <artifactId>nacos-demo</artifactId>
    <!-- Project version name snapshot version SNAPSHOT,Official version RELEASE -->
    <version>1.0-SNAPSHOT</version>

    <!-- inherit spring-boot-starter-parent rely on -->
    <!-- Use inheritance method to realize reuse, and all inheritable can be used -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
    </parent>

    <!--
        The dependent component version number is defined centrally, but is not imported,
        When a declared dependency is used in a subproject, the version number of the dependency can be omitted,
        In this way, the dependent versions used in the project can be managed uniformly
     -->
    <properties>
        <!-- Spring Cloud Hoxton.SR4 rely on -->
        <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
        <!-- spring cloud alibaba rely on -->
        <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <!-- Project dependency management the parent project only declares dependency, and the child project needs to specify the required dependency(Version information can be omitted) -->
    <dependencyManagement>
        <dependencies>
            <!-- spring cloud rely on -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- spring cloud alibaba rely on -->
            <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>
        </dependencies>
    </dependencyManagement>

</project>

  

Product service

  

Create project

  

Create a product service project under the parent project.

  

Add dependency

  

Mainly add the spring cloud starter Alibaba Nacos discovery dependency.

<!-- spring cloud alibaba nacos discovery rely on -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

The complete dependence is as follows:

<?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">
    
    <!-- Inherit parent dependency -->
    <parent>
        <artifactId>nacos-demo</artifactId>
        <groupId>com.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>product-service</artifactId>

    <!-- Project dependency -->
    <dependencies>
        <!-- spring cloud alibaba nacos discovery rely on -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- spring boot web rely on -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok rely on -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- spring boot test rely on -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>

  

configuration file

  

  application.yml

server:
  port: 7070 # port

spring:
  application:
    name: product-service # apply name
  # Configure Nacos registry
  cloud:
    nacos:
      discovery:
        enabled: true # If you do not want to use Nacos for service registration and discovery, set it to false
        server-addr: 127.0.0.1:8848 # Nacos server address

  

Entity class

  

  Product.java

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

  

Write service

  

  ProductService.java

package com.example.service;

import com.example.pojo.Product;

import java.util.List;

/**
 * Goods and services
 */
public interface ProductService {

    /**
     * Query product list
     *
     * @return
     */
    List<Product> selectProductList();

}

  ProductServiceImpl.java

package com.example.service.impl;

import com.example.pojo.Product;
import com.example.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

/**
 * Goods and services
 */
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

    /**
     * Query product list
     *
     * @return
     */
    @Override
    public List<Product> selectProductList() {
        log.info("Commodity service query commodity information...");
        return Arrays.asList(
                new Product(1, "Huawei Mobile", 1, 5800D),
                new Product(2, "Lenovo notebook", 1, 6888D),
                new Product(3, "Mi Pad ", 5, 2020D)
        );
    }

}

  

Control layer

  

  ProductController.java

package com.example.controller;

import com.example.pojo.Product;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private ProductService productService;

    /**
     * Query product list
     *
     * @return
     */
    @GetMapping("/list")
    public List<Product> selectProductList() {
        return productService.selectProductList();
    }

}

This project can be tested by unit test, or directly by url using postman or browser.

  

Startup class

  

Use the Spring Cloud native annotation @ EnableDiscoveryClient to enable service registration and discovery.

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Enable @ EnableDiscoveryClient annotation, which will be enabled by default in the current version
//@EnableDiscoveryClient
@SpringBootApplication
public class ProductServiceApplication {

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

}

  

Registration Center

  

Refresh the Nacos server, and you can see that the service is registered to Nacos.

  

Order service

  

Create project

  

Create an order service project under the parent project just now.

  

Add dependency

  

  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 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <!-- Inherit parent dependency -->
    <parent>
        <artifactId>nacos-demo</artifactId>
        <groupId>com.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>order-service</artifactId>

    <!-- Project dependency -->
    <dependencies>
        <!-- spring cloud alibaba nacos discovery rely on -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- spring boot web rely on -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok rely on -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- spring boot test rely on -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    
</project>

  

configuration file

  

  application.yml

server:
  port: 9090 # port

spring:
  application:
    name: order-service # apply name
  # Configure Nacos registry
  cloud:
    nacos:
      discovery:
        enabled: true # If you do not want to use Nacos for service registration and discovery, set it to false
        server-addr: 127.0.0.1:8848 # Nacos server address

  

Entity class

  

  Product.java

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {

    private Integer id;
    private String productName;
    private Integer productNum;
    private Double productPrice;

}

  

  Order.java

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order implements Serializable {

    private Integer id;
    private String orderNo;
    private String orderAddress;
    private Double totalPrice;
    private List<Product> productList;

}

  

Consumer services

  

  OrderService.java

package com.example.service;

import com.example.pojo.Order;

public interface OrderService {

    /**
     * Query order based on primary key
     *
     * @param id
     * @return
     */
    Order selectOrderById(Integer id);

}

  

There are three ways to achieve service consumption:

  • DiscoveryClient: obtain service information through metadata
  • LoadBalancerClient: the load balancer of Ribbon
  • @LoadBalanced: enable the Ribbon's load balancer by annotation

  

DiscoveryClient

  

Spring Boot does not provide any auto configured RestTemplate bean s, so you need to inject RestTemplate into the startup class.

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

// Enable @ EnableDiscoveryClient annotation, which will be enabled by default in the current version
//@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

  

  OrderServiceImpl.java

package com.example.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.pojo.Order;
import com.example.pojo.Product;
import com.example.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * Query order based on primary key
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        log.info("Order service query order information...");
        return new Order(id, "order-001", "China", 22788D,
                selectProductListByDiscoveryClient());
    }

    private List<Product> selectProductListByDiscoveryClient() {
        StringBuffer sb = null;

        // Get service list
        List<String> serviceIds = discoveryClient.getServices();
        if (CollectionUtils.isEmpty(serviceIds))
            return null;

        // Get service by service name
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances("product-service");
        if (CollectionUtils.isEmpty(serviceInstances))
            return null;

        // Build remote service call address
        ServiceInstance si = serviceInstances.get(0);
        sb = new StringBuffer();
        sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list");
        log.info("Order service calls commodity service...");
        log.info("The product service address obtained from the registration center is:{}", sb.toString());

        // Remote call service
        // ResponseEntity: encapsulates the return data
        ResponseEntity<List<Product>> response = restTemplate.exchange(
                sb.toString(),
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {});
        log.info("The query results of commodity information are:{}", JSON.toJSONString(response.getBody()));
        return response.getBody();
    }

}

  

LoadBalancerClient

  

  OrderServiceImpl.java

package com.example.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.pojo.Order;
import com.example.pojo.Product;
import com.example.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient; // Ribbon load balancer

    /**
     * Query order based on primary key
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        log.info("Order service query order information...");
        return new Order(id, "order-001", "China", 22788D,
                selectProductListByLoadBalancerClient());
    }

    private List<Product> selectProductListByLoadBalancerClient() {
        StringBuffer sb = null;

        // Get service by service name
        ServiceInstance si = loadBalancerClient.choose("product-service");
        if (null == si)
            return null;

        sb = new StringBuffer();
        sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list");
        log.info("Order service calls commodity service...");
        log.info("The product service address obtained from the registration center is:{}", sb.toString());

        // ResponseEntity: encapsulates the return data
        ResponseEntity<List<Product>> response = restTemplate.exchange(
                sb.toString(),
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {});
        log.info("The query results of commodity information are:{}", JSON.toJSONString(response.getBody()));
        return response.getBody();
    }

}

  

@LoadBalanced

  

Add @ LoadBalanced annotation when starting class to inject RestTemplate, indicating that the RestTemplate has the ability of client load balancing when requesting.

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {

    @Bean
    @LoadBalanced // Load balancing notes
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

  

  OrderServiceImpl.java

package com.example.service.impl;

import com.alibaba.fastjson.JSON;
import com.example.pojo.Order;
import com.example.pojo.Product;
import com.example.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * Query order based on primary key
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        log.info("Order service query order information...");
        return new Order(id, "order-001", "China", 22788D,
                selectProductListByLoadBalancerAnnotation());
    }

    private List<Product> selectProductListByLoadBalancerAnnotation() {
        String url = "http://product-service/product/list";
        log.info("Order service calls commodity service...");
        log.info("The product service address obtained from the registration center is:{}", url);
        // ResponseEntity: encapsulates the return data
        ResponseEntity<List<Product>> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Product>>() {});
        log.info("The query results of commodity information are:{}", JSON.toJSONString(response.getBody()));
        return response.getBody();
    }

}

  

Control layer

  

  OrderController.java

package com.example.controller;

import com.example.pojo.Order;
import com.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * Query order based on primary key
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }

}

  

visit

  

Refresh the Nacos server, and you can see that the service is registered to Nacos.

Visit: http://localhost:9090/order/1 The results are as follows:

  

Configure MySQL database

  

Before 0.7 version of Nacos, the embedded database Apache Derby was used by default to store data (the embedded database will start with Nacos without additional installation); support for MySQL data source was added in 0.7 version and later.

  

MySQL data source

  

Environment requirements: MySQL 5.6.5 + (it is recommended to use at least the active standby mode or the highly available database for production);

  

Initialize MySQL database

  

Create database nacos_config.

SQL source file address: https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql , or under the directory conf of Nacos server, find nacos-mysql.sql File, run the file, and the result is as follows:

  

application.properties to configure

  

Modify nacos/conf/application.properties The following content of the file.

The final modification results are as follows:

#*************** Config Module Related Configurations ***************#
### If user MySQL as datasource:
# Specify MySQL as the data source
spring.datasource.platform=mysql

### Count of DB:
# Number of database instances
db.num=1

# Database connection information, if MySQL version 8.0 + needs to add serverTimezone=Asia/Shanghai
### Connect URL of DB:
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&serverTimezone=Asia/Shanghai
db.user=root
db.password=1234

If you use MySQL 8.0 + as I do, there will be an error when you start Nacos. Don't panic, create the plugins/mysql folder in the Nacos installation directory, and put it in the 8.0 + version of mysql-connector-java-8.0 xx.jar , restart Nacos, and you will be prompted to change the driver class of MySQL.

Next, we will explain the construction of Nacos Registration Center cluster environment. Please pay attention to it

This paper adopts Intellectual sharing "signature - non-commercial use - no deduction 4.0 international" License Agreement.

You can go through classification See more about Spring Cloud The article.

  

🤗 Your comments and forwarding are my biggest support.

📢 Scan the code and follow Mr. halloward's "document + video". Each article is provided with a special video explanation, which makes learning easier~

Tags: Programming Spring Java Lombok MySQL

Posted on Wed, 10 Jun 2020 01:16:22 -0400 by jnewing