preface

Starting from this chapter, we learn 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 that developers can easily use to develop distributed application services through the Spring Cloud programming model.

Relying on Spring Cloud Alibaba, Spring Cloud applications can be connected to Ali Micro service solutions by adding some annotations and a small amount of configuration, and distributed application systems can be quickly built through Ali middleware.

Spring Cloud Alibaba features

  1. Sentinel: Supports access to WebServlet, WebFlux, OpenFeign, RestTemplate, Dubbo, Gateway, and Zuul traffic limiting degradation functions. Traffic limiting degradation rules can be modified in real time through the console at run time, and traffic limiting degradation metrics can be monitored.
  2. Service Registration and Discovery Nacos: It ADAPTS to the Spring Cloud Service Registration and discovery standard and integrates Ribbon support by default.
  3. Distributed Configuration Management Nacos: Supports external configuration in distributed systems and automatically refreshes when configuration changes.
  4. RPC Service Dubbo: Extend Spring Cloud clients RestTemplate and OpenFeign to support calling Dubbo RPC services.
  5. “Message Driven RocketMQ” : Build message driven capabilities for microservice applications based on Spring Cloud Stream.
  6. Distributed Transaction Seata: A distributed transaction solution that supports high performance and easy to use.
  7. Ali Cloud object storage OSS: large-scale, secure, low-cost, highly reliable cloud storage service. Supports storage and access of any type of data in any application anytime, anywhere.
  8. Distributed Task Scheduling SchedulerX: provides second-level, precise, highly reliable, and highly available scheduled (Cron expression based) task scheduling services. It also provides a distributed task execution model, such as grid tasks. Grid tasks allow quantum tasks to be evenly distributed to all workers (schedulerx-client) for execution.
  9. “Ali Cloud SMS” : global SMS service, friendly, efficient and intelligent communication capabilities, to help 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 makes it easier to build cloud native applications.
  • Sentinel: Lightweight flow control products oriented to distributed service architecture, take traffic as the entry point to protect the stability of services from multiple dimensions such as flow control, fuse downgrading, and system load protection.
  • RocketMQ: an open source distributed messaging system, based on highly available distributed clustering technology, provides low-latency, highly reliable message publishing and subscription services.
  • DubboApache Dubbo™ is a high-performance Java RPC framework.
  • Seata: Alibaba open source product, an easy-to-use high-performance microservice distributed transaction solution.
  • Alibaba Cloud ACM: An application configuration center that centrally manages and pushes application configurations in a distributed architecture.
  • Alibaba Cloud OSS: Ali Cloud Object Storage Service (OSS) is a massive, secure, low-cost and highly reliable cloud Storage Service provided by Ali Cloud. You can store and access any type of data in any application, anytime, anywhere.
  • Alibaba Cloud SchedulerX: A distributed task scheduling product developed by Ali middleware team, which provides second-level, accurate, highly reliable and highly available timed (Cron expression based) task scheduling service.
  • Alibaba Cloud SMS: Global SMS service, friendly, efficient and intelligent interconnection communication capabilities, help enterprises quickly build customer access channels.

What is a registry

Service registry is the core component of service management. Similar to directory service, it is mainly used to store service information, such as provider URL string and routing information. A service registry is one of the most basic infrastructures in a microservices architecture.

A registry is the “address book” of the microservices architecture, recording the mapping between services and service addresses. In a distributed architecture, services are registered here, and when a service needs to call another service, it finds the address of the service and makes the call.

In the absence of a registry, interservice calls need to know the address of the service caller (written IP :port). Changing the deployment address forces you to change the address specified in the call. After having the registry, each service only needs to know the service name (soft code) when calling others, and the address will be called through the registry according to the service name to obtain the specific service address.


To take a real life example, 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 him by name in the address book, and then I can find his mobile phone number to make a call. — Service discovery

Li Si got his mobile phone number and told me his phone number. I put li Si’s number in the address book, and then I can find him from the address book. — Service registration

Address book –? What role (Service Registry)

Summary: The role of a service registry is to “register services” and “discover services”.

A common registry

  • Netflix Eureka
  • Alibaba Nacos
  • HashiCorp Consul
  • Apache ZooKeeper
  • CoreOS Etcd
  • CNCF CoreDNS
features Eureka Nacos Consul Zookeeper
CAP AP CP + AP CP CP
Health check Client Beat TCP/HTTP/MYSQL/Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
Avalanche protection There are There are There is no There is no
Automatic logout instance support support Does not support support
Access protocol HTTP HTTP/DNS HTTP/DNS TCP
Listening to the support support support support support
Multi-data center support support support Does not support
Synchronization across registries Does not support support support Does not support
SpringCloud integration support support support support

CAP principle and BASE theory

The principle of CAP


The CAP principle, also known as the CAP theorem, refers to the importance of Consistency, Availability and Partition tolerance in a distributed system.

CAP was proposed by Eric Brewer at PODC 2000. This conjecture was proved to be true two years later and became known as CAP theorem. CAP can’t have all three.

features theorem
Consistency Also called data atomicity, the system remains in a consistent state after performing an operation. A distributed system in which all users should read the latest value after a successful update is performed is considered to be highly consistent. This is equivalent to all nodes accessing the same latest copy of data.
Availability Each operation can always return a result within a certain amount of time. The words “within a certain amount of time” and “return result” are important here. Within a certain amount of time means that the results are returned within tolerable limits, which can be success or failure.
Partition tolerance In the case of network partitioning, the separated nodes can still provide services normally (distributed cluster, data is distributed on different servers, servers can be accessed normally no matter what).

Trade-off strategy

Only two of the three CAP features can be satisfied, so there are three trade-offs:

  • “CA without P” : C (strong consistency) and A (availability) are guaranteed if P (partitioning is not allowed) is not required. However, giving up P means giving up the expansibility of the system, that is, the distributed nodes are limited and cannot deploy child 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 maintain strong consistency between servers, while P (partition) will lead to infinite synchronization time (that is, wait for data synchronization to complete before normal access to the service). Once network failure or message loss occurs, user experience will be sacrificed. Wait for all data to be consistent before allowing users to access the system. In fact, there are many systems designed as CP, the most typical of which is distributed database, such as Redis and HBase. For these distributed databases, data consistency is a fundamental requirement, because if this standard is not met, then simply use a relational database, and there is no need to waste resources deploying a distributed database.
  • “AP without C” : To be highly available and allow partitioning, consistency must be abandoned. Once partitioning occurs, nodes may lose contact with each other, and for high availability, each node can only serve with local data, which can lead to global data inconsistencies. A typical application is like the scene of buying up a mobile phone in a certain meter. It may be that there is stock on the page when you browse the product in the first few seconds. When you finish selecting the product and prepare to place an order, the system will prompt you that the order has failed and the product has been sold out. In fact, this is to ensure the normal service of the system in terms of A (availability), and then make some sacrifices in terms of data consistency. Although some user experience will be affected, it will not cause serious congestion in the shopping process of users.

conclusion

Nowadays, for most of the large Internet application scenarios, there are many hosts, scattered deployment, and now the cluster scale is getting larger and larger, the nodes will only be more and more, so node failure, network failure is normal, so the fault tolerance of zoning has become a distributed system must face the problem. So it’s A choice between C and A. However, traditional projects may be different. Take the transfer system of the bank as an example, the consistency of data involving money cannot be compromised at all. C must ensure that it would rather stop service if there is A network failure, and it can make A choice between A and P.

All in all, there is no best strategy, a good system should be architected according to the business scenario, and only the right one is the best.

The BASE theory of

CAP theory has been around for years. Is there really no way to solve this problem? Maybe some changes can be made. For example, C doesn’t have to be so consistent. It can save the data and update it later, achieving what is called “final consistency.”

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

BASE: Abbreviation for Basically Available, Soft state, and Eventually consistent, coined by the architects of ebay.

BASE theory is the result of tradeoff between consistency and availability in CAP. It is derived from the summary of distributed practice of large-scale Internet and gradually evolved based on CAP theorem. Its core idea is:

Since Strong consistency cannot be achieved, each application can adopt an appropriate method to achieve Eventual consistency according to its own service characteristics.

Basically Available

Basic availability is the ability of a distributed system to allow a partial loss of availability (such as response time, functional availability) in the event of a failure. It is important to note that being basically available is by no means the same as not being available.

  • Loss in response time: Normally, the search engine returns the search results to users within 0.5 seconds. However, due to faults (such as power failure or network disconnection in some equipment rooms of the system), the response time of the search results increases to 1 to 2 seconds.
  • Loss of functionality: Some consumers may be directed to a degraded page during peak shopping hours (such as Singles’ Day) in order to protect the stability of the system.

Soft state

What is a soft state? In contrast to atomicity, requiring that copies of data across multiple nodes be consistent is a “hard state.”

A soft state is one that allows the system to have intermediate states that do not affect the overall availability of the system. Generally, one copy of data in distributed storage has multiple copies. The delay of data synchronization between different copies is a manifestation of soft state.

Eventually consistent

Systems can’t be soft all the time. There has to be a time limit. After the expiration of the period, data consistency should be guaranteed for all copies. To achieve the final consistency of data. This time frame depends on network latency, system load, data replication scheme design, and so on.

In fact, not only distributed systems use final consistency, but also relational databases use final consistency for certain functions, such as backup and database replication, which take time. During the replication process, the business reads the old value. Of course, data consistency was eventually achieved. This is also a classic case of ultimate consistency.

conclusion

In general, BASE theory is oriented towards large, highly available and scalable distributed systems, which is the opposite of ACID of traditional transactions. It is completely different from ACID’s strong consistency model, but gains availability by sacrificing strong consistency and allows data to be inconsistent for a period of time.

Why do you need a registry

Now that we know what a registry is, let’s move on to why we need one. In distributed systems, there are more complex issues to consider than simply finding a mapping between a service and its address in a registry:

  • How can services be discovered after registration
  • How can I log out of a service in a timely manner
  • How can services scale horizontally effectively
  • How to route a service when it is discovered
  • How can I degrade a service when it is abnormal
  • How can registries make themselves highly available

The resolution of these problems depends on the registry. Registry functions like a DNS server or a load balancer, but in reality, as a basic component of microservices, registries can be more complex and require more flexibility and timeliness. Therefore, we still need to learn more Spring Cloud microservice components to cooperate with application development.

The registry addresses the following issues:

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

Nacos introduction


Nacos is an open source tool launched by Alibaba for service discovery and configuration management of distributed systems. Dynamic Naming and Configuration Service, Na /NameServer, CO Configuration, Service indicates that the registry/configuration center is service-centered. Service is a first-class citizen of the Nacos world.

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

Nacos is dedicated to discovering, configuring, and managing microservices. Nacos provides an easy-to-use feature set to quickly implement dynamic service discovery, service configuration, service metadata, and traffic management.

Nacos makes it more agile and easy to build, deliver, and manage microservices platforms. Nacos is the service infrastructure for building a modern “service” -centric application architecture.

Using Nacos simplifies service discovery, configuration management, service governance, and management solutions, making it easier to discover, manage, share, and compose microservices.

Nacos website: https://nacos.io/zh-cn/

Github:https://github.com/alibaba/nacos

Nacos installation

Environment to prepare

Nacos relies on the Java environment to run. If you build and run Nacos from code and need to configure the Maven environment for this, make sure you install it in one of the following versions:

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

Download the source code or install the package

Nacos can be obtained from both source code and distribution packages.

Source way

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 Copy the code

Distribution package

You can download the latest stable version from https://github.com/alibaba/nacos/releases nacos – server package.

Start the server

Linux/Unix/Mac

Start in the Nacos /bin directory.

Startup command (standalone stands for standalone mode, not cluster mode) :

sh startup.sh -m standalone
Copy the code

If you are using Ubuntu or cannot find the error symbol when you run the script, try the following:

bash startup.sh -m standalone
Copy the code

Windows

Start command:

cmd startup.cmd
Copy the code

Or double-click the startup. CMD file to run it.

access

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



Shut down the server

Linux/Unix/Mac

sh shutdown.sh
Copy the code

Windows

cmd shutdown.cmd
Copy the code

Or double-click the shutdown.cmd file to run it.

An introduction to Nacos

Create a project

We created an aggregation project to illustrate Nacos, starting with a POM parent project.



Add the dependent

pom.xml


      
<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, official version RELEASE -->  <version>1.0 the SNAPSHOT</version>   <! -- Inherits spring-boot-starter-parent dependency -->  <! -- Use inheritance mode, implement reuse, conform to inheritance can be used -->  <parent>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-parent</artifactId>  <version>2.3.0. RELEASE</version>  </parent>   <! --Centrally define dependent component versions without introducing,When a declared dependency is used in a subproject, the version number of the dependency can be omitted.This allows unified management of the dependent versions used in the project -->  <properties>  <! -- Spring Cloud hoxton.sr4 dependencies -->  <spring-cloud.version>Hoxton.SR4</spring-cloud.version>  <! -- Spring Cloud Alibaba -->  <spring-cloud-alibaba.version>2.1.0. RELEASE</spring-cloud-alibaba.version>  </properties>   <! Project dependency management The parent project only declares dependencies. The child project needs to specify the required dependencies (omit version information).  <dependencyManagement>  <dependencies>  <! -- Spring Cloud dependencies -->  <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 -->  <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> Copy the code

Product-service

Create a project

Create a product-Service project under the parent project.


Add the dependent

Add the spring-cloud-starter-Alibaba-nacos-discovery dependency.

<! -- Spring Cloud Alibaba NacOS Discovery
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
Copy the code

Complete dependencies are as follows:


      
<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">
    
 <! -- Inheriting parent dependencies -->  <parent>  <artifactId>nacos-demo</artifactId>  <groupId>com.example</groupId>  <version>1.0 the SNAPSHOT</version>  </parent>  <modelVersion>4.0.0</modelVersion>   <artifactId>product-service</artifactId>   <! -- Project dependencies -->  <dependencies>  <! -- Spring Cloud Alibaba NacOS Discovery  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>  </dependency>  <! Spring Boot Web dependency -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <! -- Lombok dependency -->  <dependency>  <groupId>org.projectlombok</groupId>  <artifactId>lombok</artifactId>  <scope>provided</scope>  </dependency>   <! -- Spring Boot test dependency -->  <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> Copy the code

The configuration file

application.yml

server:
  port: 7070 # port

spring:
 application:
 name: product-service # app name  Configure the Nacos registry  cloud:  nacos:  discovery:  enabled: true If you don't want to use Nacos for service registration and discovery, set it to false  server-addr: 127.0. 01.: 8848 # Nacos server address  Copy the code

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;  } Copy the code

Write the service

ProductService.java

package com.example.service;

import com.example.pojo.Product;

import java.util.List;
 / * ** Goods and services* / public interface ProductService {   / * ** Query the list of goods *  * @return * /  List<Product> selectProductList(a);  } Copy the code

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 the list of goods *  * @return * /  @Override  public List<Product> selectProductList(a) {  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."Xiaomi Tablet".5.2020D)  );  }  } Copy the code

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 the list of goods *  * @return * /  @GetMapping("/list")  public List<Product> selectProductList(a) {  return productService.selectProductList();  }  } Copy the code

This project can be tested by unit testing, or directly by URL using Postman or browser.

Start the class

Enable service registration discovery through the Spring Cloud native annotation @enableDiscoveryClient.

package com.example;

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

// Enable the @enableDiscoveryClient annotation. This annotation is enabled by default in the current version //@EnableDiscoveryClient @SpringBootApplication public class ProductServiceApplication {   public static void main(String[] args) {  SpringApplication.run(ProductServiceApplication.class, args);  }  } Copy the code

The registry

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


Order service order-service

Create a project

Create an order-service project under the parent project.


Add the dependent

pom.xml


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

 <! -- Inheriting parent dependencies -->  <parent>  <artifactId>nacos-demo</artifactId>  <groupId>com.example</groupId>  <version>1.0 the SNAPSHOT</version>  </parent>  <modelVersion>4.0.0</modelVersion>   <artifactId>order-service</artifactId>   <! -- Project dependencies -->  <dependencies>  <! -- Spring Cloud Alibaba NacOS Discovery  <dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>  </dependency>  <! Spring Boot Web dependency -->  <dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <! -- Lombok dependency -->  <dependency>  <groupId>org.projectlombok</groupId>  <artifactId>lombok</artifactId>  <scope>provided</scope>  </dependency>   <! -- Spring Boot test dependency -->  <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> Copy the code

The configuration file

application.yml

server:
  port: 9090 # port

spring:
 application:
 name: order-service # app name  Configure the Nacos registry  cloud:  nacos:  discovery:  enabled: true If you don't want to use Nacos for service registration and discovery, set it to false  server-addr: 127.0. 01.: 8848 # Nacos server address Copy the code

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;  } Copy the code

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;  } Copy the code

Consumer services

OrderService.java

package com.example.service;

import com.example.pojo.Order;

public interface OrderService {
  / * ** Query orders based on primary keys *  * @param id  * @return * /  Order selectOrderById(Integer id);  } Copy the code

There are three ways to realize service consumption:

  • DiscoveryClient: Obtains service information through metadata
  • LoadBalancerClient: Load balancer for the Ribbon
  • LoadBalanced: Enable load balancer in the Ribbon with annotations
DiscoveryClient

Spring Boot does not provide any auto-configured RestTemplate Beans, so you need to inject RestTemplate into the Boot 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 the @enableDiscoveryClient annotation. This annotation is enabled by default in the current version //@EnableDiscoveryClient @SpringBootApplication public class OrderServiceApplication {   @Bean  public RestTemplate restTemplate(a) {  return new RestTemplate();  }   public static void main(String[] args) {  SpringApplication.run(OrderServiceApplication.class, args);  }  } Copy the code

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 orders based on primary keys *  * @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(a) {  StringBuffer sb = null;   // Get the list of services  List<String> serviceIds = discoveryClient.getServices();  if (CollectionUtils.isEmpty(serviceIds))  return null;   // Get the service by the service name  List<ServiceInstance> serviceInstances = discoveryClient.getInstances("product-service");  if (CollectionUtils.isEmpty(serviceInstances))  return null;   // Build the remote service invocation address  ServiceInstance si = serviceInstances.get(0);  sb = new StringBuffer();  sb.append("http://" + si.getHost() + ":" + si.getPort() + "/product/list");  log.info("Order service invokes goods service...");  log.info("The commodity service address obtained from the registry is: {}", sb.toString());   // Call the service remotely  // ResponseEntity: encapsulates the returned data  ResponseEntity<List<Product>> response = restTemplate.exchange(  sb.toString(),  HttpMethod.GET,  null. new ParameterizedTypeReference<List<Product>>() {});  log.info("Product information query result: {}", JSON.toJSONString(response.getBody()));  return response.getBody();  }  } Copy the code

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 orders based on primary keys *  * @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(a) {  StringBuffer sb = null;   // Get the service by the 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 invokes goods service...");  log.info("The commodity service address obtained from the registry is: {}", sb.toString());   // ResponseEntity: encapsulates the returned data  ResponseEntity<List<Product>> response = restTemplate.exchange(  sb.toString(),  HttpMethod.GET,  null. new ParameterizedTypeReference<List<Product>>() {});  log.info("Product information query result: {}", JSON.toJSONString(response.getBody()));  return response.getBody();  }  } Copy the code

@LoadBalanced

The @loadBalanced load balancing annotation is added when the class is started to inject the RestTemplate to indicate that the RestTemplate has client-side load balancing capability on request.

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 annotations  public RestTemplate restTemplate(a) {  return new RestTemplate();  }   public static void main(String[] args) {  SpringApplication.run(OrderServiceApplication.class, args);  }  } Copy the code

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 orders based on primary keys *  * @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(a) {  String url = "http://product-service/product/list";  log.info("Order service invokes goods service...");  log.info("The commodity service address obtained from the registry is: {}", url);  // ResponseEntity: encapsulates the returned data  ResponseEntity<List<Product>> response = restTemplate.exchange(  url,  HttpMethod.GET,  null. new ParameterizedTypeReference<List<Product>>() {});  log.info("Product information query result: {}", JSON.toJSONString(response.getBody()));  return response.getBody();  }  } Copy the code

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 orders based on primary keys *  * @param id  * @return * /  @GetMapping("/{id}")  public Order selectOrderById(@PathVariable("id") Integer id) {  return orderService.selectOrderById(id);  }  } Copy the code

access

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


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


Configuring the MySQL Database

Nacos prior to version 0.7 used an embedded database, Apache Derby, to store data by default (the embedded database started with Nacos without additional installation). Support for MySQL data sources was added in version 0.7 and later.

MySQL data source

Environment requirements: MySQL 5.6.5+ (You are advised to use the production database in active/standby mode or a high availability database);

Initialize the MySQL database

Create the database nacOS_config.

SQL source file address: https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql, or on nacos – decompression under the conf directory server, Find the nacos-mysql.sql file and run it as follows:


Application. The properties configuration

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


The final modification result is as follows:

#*************** Config Module Related Configurations ***************# ### If user MySQL as datasource: # specify the data source for MySQL spring. The datasource. Platform = MySQL

Count of DB:

Number of database instances

db.num=1

ServerTimezone =Asia/Shanghai if MySQL 8.0+ is used

Connect URL of DB:

Copy the code

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, like me, you use MySQL 8.0+, you’ll get an error when you start Nacos. Add 8.0+ mysql-connector-java-8.0.xx.jar and restart Nacos. The driver-class of MySQL has been changed.


In the next article, we will explain how to set up a cluster environment for the Nacos registry


This article is licensed under a Creative Commons attribution – Noncommercial – No Deductive 4.0 International license.

You can see more articles about Spring Cloud in the category.

🤗 your likes and retweets are the biggest support for me.

📢 Scan code pay attention to Mr. Hallward “document + video” each article is equipped with a special video explanation, learning more easily oh ~