Spring Cloud --- Feign remote call

1. RestTemplate problem

Let's first look at the code we used to initiate remote calls using RestTemplate:

There are following problems:

  • Poor code readability and inconsistent programming experience
  • URLs with complex parameters are difficult to maintain

Feign is a declarative http client, official address: GitHub - OpenFeign/feign: Feign makes writing java http clients easier

Its role is to help us elegantly implement the sending of http requests and solve the problems mentioned above.

 

 

2. Feign replaces RestTemplate

The steps to use Fegin are as follows

1) Introduce dependencies


We introduce the feign dependency in the pom file of the order-service service:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2) Add annotations


Add annotations to the startup class of order-service to enable the function of Feign:


3) Write Feign's client


Create a new interface in order-service with the following content:

package cn.itcast.order.client;

import cn.itcast.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("userservice")
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

This client is mainly based on SpringMVC annotations to declare remote call information, such as:

  • Service name: userservice

  • Request method: GET

  • Request path: /user/{id}

  • Request parameter: Long id

  • Return value type: User

In this way, Feign can help us send http requests without using RestTemplate to send them ourselves


4) test


Modify the queryOrderById method in the OrderService class in order-service, and use Feign client instead of RestTemplate:

Doesn't it look more elegant.


5) Summary


Steps to use Feign:

  1. Introduce dependencies
  2. Add @EnableFeignClients annotation
  3. Write the FeignClient interface
  4. Use methods defined in FeignClient instead of RestTemplate

 

 

3. Custom configuration

Feign can support many custom configurations, as shown in the following table:

type effect illustrate
feign.Logger.Level Modify log level Contains four different levels: NONE, BASIC, HEADERS, FULL
feign.codec.Decoder Parser for the response result Parsing the results of http remote calls, such as parsing json strings into java objects
feign.codec.Encoder request parameter encoding Encode request parameters for sending via http requests
feign. Contract Supported Annotation Formats The default is the annotation of SpringMVC
feign. Retryer Failure retry mechanism The retry mechanism for request failure, the default is no, but Ribbon's retry will be used

Under normal circumstances, the default value is enough for us to use. If you want to customize it, you only need to create a custom @Bean to override the default Bean.

The following uses logs as an example to demonstrate how to customize the configuration.

configuration file method


Modifying feign's log level based on the configuration file can target a single service:

feign:  
  client:
    config: 
      userservice: # 针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

It is also possible to target all services:

feign:  
  client:
    config: 
      default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        loggerLevel: FULL #  日志级别 

The log level is divided into four types:

  • NONE: Do not record any log information, which is the default value.

  • BASIC: Only log the request method, URL, response status code and execution time

  • HEADERS: On the basis of BASIC, the header information of the request and response is additionally recorded

  • FULL: Record details of all requests and responses, including header information, request body, and metadata.


Java code method


You can also modify the log level based on Java code, first declare a class, and then declare a Logger.Level object:

public class DefaultFeignConfiguration  {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC; // 日志级别为BASIC
    }
}

If you want to take effect globally , put it in the @EnableFeignClients annotation of the startup class:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class) 

If it is locally effective , put it in the corresponding @FeignClient annotation:

@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class) 

 

 

Four, Feign use optimization

The bottom layer of Feign initiates http requests and relies on other frameworks. Its underlying client implementation includes:

  • URLConnection: default implementation, does not support connection pooling
  • Apache HttpClient: support connection pool
  • OKHttp: support connection pool

Therefore, the main means to improve the performance of Feign is to use the connection pool instead of the default URLConnection.

Here we use Apache's HttpClient to demonstrate.

1) Introduce dependencies

Introduce Apache's HttpClient dependency in the pom file of order-service:

<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

2) Configure the connection pool

Add configuration in application.yml of order-service:

feign:
  client:
    config:
      default: # default全局的配置
        loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 最大的连接数
    max-connections-per-route: 50 # 每个路径的最大连接数

Next, break in the loadBalance method in FeignClientFactoryBean:

Start the order-service service in Debug mode, you can see the client here, the bottom layer is Apache HttpClient:

In summary, Feign's optimization:

1. Try to use basic as the log level

2. Use HttpClient or OKHttp instead of URLConnection

  • Introduce feign-httpClient dependency
  • The configuration file enables the httpClient function and sets the connection pool parameters

 

 

5. Best Practices

The so-called recent practice refers to the experience summed up during the use process, the best way to use it.

Self-study observation shows that Feign's client is very similar to the controller code of the service provider:

feign client:

UserController:

Is there a way to simplify this repetitive coding?

 

5.1. Inheritance method

The same code can be shared through inheritance:

1) Define an API interface, use the definition method, and make a statement based on SpringMVC annotations.

2) Both the Feign client and the Controller integrate the interface

advantage:

  • Simple

  • code sharing

shortcoming:

  • Service provider and service consumer are tightly coupled

  • The annotation mapping in the parameter list will not be inherited, so the method, parameter list, and annotation must be declared again in the Controller

  

5.2. Extraction method

Extract Feign's Client as an independent module, and put the interface-related POJO and default Feign configuration into this module for all consumers to use.

For example, the default configurations of UserClient, User, and Feign are all extracted into a feign-api package, and all microservices can be used directly by referencing this dependency package.

 

5.3. Implement extraction-based best practices

1) extraction


First create a module named feign-api:

Project structure:

 

In feign-api, then introduce feign's starter dependency

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

Then, the UserClient, User, and DefaultFeignConfiguration written in order-service are all copied to the feign-api project

 


2) Use feign-api in order-service


First, delete classes or interfaces such as UserClient, User, and DefaultFeignConfiguration in order-service.

   

Introduce the dependency of feign-api in the pom file of order-service:

<dependency>
    <groupId>cn.itcast.demo</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0</version>
</dependency>

Modify all the package import parts related to the above three components in order-service, and change it to import the package in feign-api


3) Restart the test


After restarting, it was found that the service reported an error:

This is because UserClient is now under the cn.itcast.feign.clients package,

The @EnableFeignClients annotation of order-service is under the cn.itcast.order package, not in the same package, and UserClient cannot be scanned.


4) Solve the problem of scanning package


method one:

Specify the packages that Feign should scan:

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

Method 2:

Specify the Client interface that needs to be loaded:

@EnableFeignClients(clients = {UserClient.class})

Guess you like

Origin blog.csdn.net/a1404359447/article/details/130347567