SpringCloud Tutorial | Chapter 2: Service Consumers (RestTemplate and Feign)

I have recently learned about Spring Cloud and benefited a lot. I would like to record my learning process with this series of blog posts, and also provide some reference for everyone to learn Spring Cloud. The blog post will be updated in due course according to the learning progress.

In the previous chapter, you learned about service registration and discovery (Eureka). In the microservice architecture, the overall business will be split into individual services, and the communication between services is based on Http RESTful. Spring cloud has two service calling methods, one is Ribbon+RestTemplate, and the other is Feign. Both will be covered in this blog post.

I. Introduction

1.1 Introduction to RESTful

RESTful is currently the most popular API design specification for the design of Web data interfaces.

The RESTful architecture is the implementation of the REST-style architecture. The REST principle mainly includes two aspects, the request description and the return description of the URL interface. The request description includes interface design, received parameter types, received data format, calling method (Get/Post), etc.; the return description includes return status code, returned data format, etc.

In fact, in the SpringMVC we are familiar with, the REST-style architecture design has been natively supported. Here are a few commonly used annotations:

@RequestMapping

RequestMapping can identify the request mode of the interface, Get|Post|Delete, etc.; it can also receive data in different formats, xml or json;

@PathVariable

PathVariable can identify the data type, parameter name, etc. of the parameters accepted by the interface;

@ResponseBody

ResponseBody can define the data format returned by the interface, etc.;

At the same time, it also defines the status code of the HTTP response, 200/500/404 and so on.

In short, the communication between services in the SpringCloud microservice architecture is based on RESTful, which means that the calls between services meet the HTTP communication principle.

1.2 Introduction to Ribbon

Spring Cloud Ribbon is a client load balancing tool based on HTTP and TCP, which is implemented based on Netflix Ribbon. Through the encapsulation of Spring Cloud, we can easily convert service-oriented REST template requests into client-side load-balanced service calls. Spring Cloud Ribbon is a tool framework. It does not need to be deployed independently like the service registry, configuration center, and API gateway. It can be said that it exists in almost every microservice and infrastructure built by Spring Cloud. Because the calls between microservices, the request forwarding of the API gateway, etc., are actually implemented through the Ribbon, and Feign is also a tool based on the Ribbon. Therefore, the understanding and use of Spring Cloud Ribbon is very important for us to use Spring Cloud to build microservices.

1.3 Introduction to RestTemplate

Spring RestTemplate is a client provided by Spring for accessing Rest services. Before we initiate HTTP requests, we may use HTTPClient, HttpURLConnection, etc. Now Spring has encapsulated this HTTP interaction framework for us. RestTemplate provides a variety of convenient methods for accessing remote Http services, which can greatly improve the writing efficiency of clients, so many clients such as Android or third-party service providers use RestTemplate to request RESTful services.

1.4 Introduction to Spring Cloud Feign

Spring Cloud Feign is implemented based on Netflix feign, which integrates Spring Cloud Ribbon and Spring Cloud Hystrix (circuit breaker, which will be discussed later). In addition to providing the powerful functions of the two, it also provides a declarative Web service client definition The way.

Spring Cloud Feign helps us define and implement the definition of dependent service interfaces. Under the implementation of Spring Cloud feign, you only need to create an interface and configure it with annotations to complete the interface binding of the service provider.

Spring Cloud Feign has pluggable annotation support, supports Feign annotations, JAX-RS annotations and Spring MVC annotations.

Compared with RestTemplate, Feign has the following advantages:

1. Use annotations to implement declarative calls. Supports multiple annotations, which simplifies the development of self-encapsulated service calling clients, and also makes the code concise and elegant;

2. Spring Cloud Feign integrates Ribbon and Hystrix to easily implement load balancing and fuse mechanism;

3. It is more suitable for communication between services in large-scale projects. Calls between services, message synchronization, etc.

2. Preparation

This blog post builds on the project created in the previous blog post. Start the eureka-server project; start the eureka-client project, its port is 8762; change the port in the eureka-client configuration file to 8763, and then start a eureka-client, then you will find: eureka-client is in eureka -There are 2 instances registered in the server, which is equivalent to a small cluster.

How to start multiple instances under idea, see the figure below:

Click Edit Configurations

Remove the √ in front of Single instance only:

Open a browser to access localhost:8761, as shown in the figure:

3. Two service calling methods

3.1 Ribbon+RestTemplate

3.1.1 create service-ribbon module

Create a new spring-boot module project in moi-sc-parent, named: service-ribbon;
its pom.xml inherits the parent pom file and introduces other dependencies. The detailed code 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">
    <parent>
        <artifactId>moi-sc-parent</artifactId>
        <groupId>com.moi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-ribbon</artifactId>
    <packaging>jar</packaging>

    <name>service-ribbon</name>
    <description>ribbon project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
    </dependencies>
</project>

3.1.2 service-ribbon application.yml

In the service-ribbon configuration file, specify the registry address of the service as http://localhost:8761/eureka/, the program name as service-ribbon, and the program port as 8764. The configuration file application.yml is as follows:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8764
spring:
  application:
    name: service-ribbon
info:
  app.name: atguigu-microservicecloud
  company.name: www.atguigu.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$

3.1.3 service-ribbon startup class

In the startup class of service-ribbon, register with the service center through @EnableEurekaClient; then inject a bean into the ioc container: restTemplate; and indicate that this restRemplate enables load balancing through the @LoadBalanced annotation. code show as below:

package com.moi;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * Created by fangw on 2019/2/19.
 */
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run( ServiceRibbonApplication.class, args );
    }

    @Bean
    @LoadBalanced
    restTemplate restTemplate() {
        return new RestTemplate();
    }
    @Value("${server.port}")
    String port;

    @RequestMapping("/hello")
    public String home(@RequestParam(value = "name", defaultValue = "fangw") String name) {
        return "hi " + name + " ,i am from port:" + port;
    }
}

Note: Both @EnableEurekaClient and @EnableDiscoveryClient annotations can register service instances to the registry. The difference is that @EnableEurekaClient can only be registered to the Eureka registry, and @EnableDiscoveryClient can also register services to other registry centers.

3.1.4 Create a new Service class consumer service

Create a new test class HelloService, and consume the "/hi" interface of the eureka-client service through the restTemplate injected into the ioc container before. In the ribbon, it will select a specific service instance according to the service name. When requesting a service instance, it will replace the service name with a specific url. The code is as follows:

package com.moi.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * Created by fangw on 2019/2/19.
 */
@Service
public class HelloService {
    @Autowired
    restTemplate restTemplate;
    public String hiService(String name) {
        return restTemplate.getForObject("http://eurka-client/hi?name="+name,String.class);
    }
}

Note:

1. Here you can see that eurka-client is used when calling the service, which is one letter e less than the project name eureka-client. So the service instance name refers to the spring.application.name set in application.yml, not the project name;

2. The service name here is not case-sensitive, and the instance can also be accessed by using EURKA-CLIENT.

3.1.5 Create a new controller class publishing interface

Create a new controller, and use the method of calling HelloService in the controller. The code is as follows:

package com.moi.controller;

import com.moi.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by fangw on 2019/2/19.
 */
@RestController
public class HelloControler {

    @Autowired
    HelloService helloService;

    @RequestMapping(value = "/hi")
    public String hi(@RequestParam(value = "name", defaultValue = "fangw") String name) {
        return helloService.hiService( name );
    }
}

The service-ribbon project structure is as follows:

3.1.6 Results

Start service-ribbon, visit http://localhost:8764/hi?name=fangw multiple times on the browser, the browser displays alternately:

In summary, Ribbon+RestTemplate realizes the load call of the service, which is summarized as follows:

1. The RestTemplate tool initiates an HTTP request. In this article, the service instance name is used to locate a specific service;

2. Ribbon plays a load balancing effect, which is realized by using the annotation @LoadBalanced.

3.2 Feign declarative call

3.2.1 create service-feign module

Create a new spring-boot module project in moi-sc-parent, named: service-feign;
its pom.xml inherits the parent pom file and introduces other dependencies. The detailed code 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">
    <parent>
        <artifactId>moi-sc-parent</artifactId>
        <groupId>com.moi</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-feign</artifactId>
    <packaging>jar</packaging>

    <name>service-feign</name>
    <description>feign project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
</project>

3.2.2 service-feign application.yml

In the service-feign configuration file, specify the registry address of the service as http://localhost:8761/eureka/, the program name as service-feign, and the program port as 8765. The configuration file application.yml is as follows:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8765
spring:
  application:
    name: service-feign

3.2.3 service-feign startup class

In the startup class of service-feign, register with the service center through @EnableEurekaClient; then enable the Feign function through the @EnableFeignClients annotation. code show as below:

package com.moi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * Created by fangw on 2019/2/19.
 */
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ServiceFeignApplication {

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

3.2.4 Create a new Feign interface consumer service

Create a new Feign interface, and use @FeignClient ("service name") to specify which service to call. For example, to call the "/hi" interface of the eurka-client service, the code is as follows:

package com.moi.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by fangw on 2019/2/19.
 */
@FeignClient(name = "eurka-client")
public interface ServiceHi {
    @RequestMapping(value = "/hi")
    String sayHiFromClient(String name);
}

3.2.5 Create a new controller publishing interface

Create a new controller class, expose a "/hi" API interface, and consume services through the Feign client ServiceHi defined above. code show as below:

package com.moi.controller;

import com.moi.service.ServiceHi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by fangw on 2019/2/19.
 */
@RestController
public class HelloController {
    @Autowired
    ServiceHi serviceHi;

    @RequestMapping(value = "/hi")
    public String sayHi(String name) {
        return serviceHi.sayHiFromClient( name );
    }
}

3.2.6 Results

Start service-feign, visit http://localhost:8765/hi?name=fangw multiple times on the browser, the browser displays alternately:

In summary, Feign implements the load call of the service, which is summarized as follows:

1. Feign uses annotations to implement declarative calls. Support multiple annotations, the code is concise and extensible;

2. Feign integrates Ribbon to easily achieve load balancing;

3. The bottom layer of Feign is also an http service called by HttpClient.

4. Expansion

In actual project development, it is recommended to use the Feign method for communication between services. Currently commonly used structures are as follows:

If service A calls service B, the above flow chart describes:

1. Create a new springboot project and name it ExterInterfaceApi. This project is only responsible for defining the api interface, the code is similar to the 3.2.4 ServiceHi class above, but there is no FeignClient annotation. After the development is completed, it is packaged into a jar package, which is the interface jar in the above figure. The reference code is as follows:

2. Both A and B depend on the interface jar in 1. The newly created interface implementation class in B is used to implement the methods in ExterInterfaceApi. The newly created subclass interface in A inherits the interface in ExterInterfaceApi. Here, the subclass interface needs to be annotated with FeignClient. The reference code is as follows:

Implementation class:

Subclass interface:

3. In this way, the subclass interface in A can call the method of the parent class in ExterInterfaceApi. When using it, you only need to inject the subclass interface. Reference Code:

Then behaviorApiFeignClient.getUserInfo(xxxx) implements the interface call.

The above is SpringCloud Tutorial | Chapter 2: Service Consumers (RestTemplate and Feign). Welcome to leave a message in the comment area, I will reply as soon as possible~~~

Finally, play a wave of advertising. Search the public account "Buy and save" on WeChat, and get coupons when you shop on Taobao, and you can save money when you shop.

 

Guess you like

Origin blog.csdn.net/fanguoddd/article/details/87718199