Feign study notes

Posted by Spaceboy on Tue, 28 Dec 2021 06:54:03 +0100

Feign declarative remote call

1. Introduction

Feign is a declarative HTTP client. Its purpose is to make remote calls easier. Feign provides the template of HTTP request. By writing a simple interface and inserting annotations, you can define the parameters, format, address and other information of HTTP request.
Feign integrates Ribbon (load balancing) and hystrix (service fusing), so that we no longer need to explicitly use these two components.
Spring cloudfeign extends the support for spring MVC annotation on the basis of NetflixFeign. Under its implementation, we only need to create an interface and configure it in the way of annotation to complete the interface binding to the service provider. It simplifies the development of spring cloudribbon's self encapsulated service call client

2. How to use it?

Steps:

  • Guide Package
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • Create an interface and add @ FeignClient(name = "service name to be called") to the interface

  • Add EnableClients(basePackages = "package name of feign interface") to the startup class

    Summary:
    It is recommended to use the modular method. When writing a service, the service is divided into three modules:

    • The clien module is used to place the feign interface so that other services can rely on it directly
    • The common module is used to store some entity classes or tools common to each microservice
    • server module service core module
      For example:

3. Composition


The attributes listed above can be referenced Feign official website configuration Configure
principle

4.Feign log

Feign does not output logs by default. How to configure log output for feign?

Refer to the official website: Configure feign logs on the official website

Feign's log level:

levelprint contents
None (default)No logs are logged
BASICOnly record the request method, URL, response status code and execution time (most commonly used)
HEADERSRecord the header of request and response based on the BASIC level
FULLRecord the header, body and metadata of the request and response

Problem 1: fine grained configuration

Use Java code to make the specific Feign interface Full log level
Solution 1:

// Customize an interface:
@FeignClient(name = "user-center",configuration = UserCenterFeignConfiguration.class)
public interface UserCenterFeignClient {

    /**
     * http://user-center/users/{id}
     * @param id
     * @return
     */
    @GetMapping("/users/{id}")
    UserDTO findById(@PathVariable Integer id);
}

/**
Write another configuration class:
The Configuration class is not annotated with @ Configuration, otherwise it must be moved outside the package scanned by @ Component. If it is added and not moved outside the package scanned above, the log level of all Feign defined by us will be FULL. This problem is a typical parent-child context problem
*/
public class UserCenterFeignConfiguration {
    @Bean
    public Logger.Level level() {
        return Logger.Level.FULL;
    }
}

// Finally, we need to add configuration to the configuration file to make complaints about it.
logging:
  level:
/**The purpose of adding the full path of feign interface here is that if you want to print feign logs, you must establish the log level of feign interface as debug*/
    com:
      ray:
        content_center:
          feignclient:
            UserCenterFeignClient: debug

Solution 2: attribute configuration method

@FeignClient(name = "user-center")
public interface UserCenterFeignClient {

    /**
     * http://user-center/users/{id}
     * @param id
     * @return
     */
    @GetMapping("/users/{id}")
    UserDTO findById(@PathVariable Integer id);
}

feign:
  client:
    config: 
      #The name of the micro service you want to call
     user-center:
       loggerLevel: full

Question 2: global configuration

Implement all Feign interfaces in Java code to specify the log level

  • Method 1: the parent-child context problem of our fine-grained configuration above (not recommended)
  • Method 2: in @ EnableFeignClients(defaultConfiguration=xxx.class)
    public class xxx {
          @Bean
          public Logger.Level level() {
              return Logger.Level.FULL;
          }
      }
    
    Configure attribute mode
    	feign:
      	  client:
      	    config:
      	      #Global configuration
      	     default:
      	       loggerLevel: full
    

5. Configuration best practice summary


6. Multi parameter request construction

Tips: Version: Spring Cloud Greenwich SR1, which theoretically supports higher versions

GET request multi parameter URL

Suppose that the URL to be requested contains multiple parameters, such as http://localhost:8080/get?id=1&userName= "ray", how to use Feign construction?

Through the official website, we know that Feign has added annotation support for Spring MVC: then try a wave

public class User{
	String userName;
	Long id;
}

@FeignClient("user-service")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get(User user);
}

However, this method is not correct. The console outputs the following exceptions:

feign.FeignException: status 405 reading UserFeignClient#get0(User); content:
{"timestamp":1482676142940,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/get"}

It can be seen from the exception that Feign will still send the request using the POST method even though we specify the GET method

The correct wording is as follows:

  • Mode 1: Recommended on the official website
    @FeignClient("user-service")
    	public interface UserFeignClient {
    	  @GetMapping("/get")
    	  public User get(@SpringQueryMap User user);
    }
    
  • Mode 2:
    @FeignClient(name = "user-service")
    public interface UserFeignClient {
      @RequestMapping(value = "/get", method = RequestMethod.GET)
      public User get(@RequestParam("id") Long id, @RequestParam("username") String userName);
    }
    

The POST request contains multiple parameters

Suppose the Controller of the service provider is as follows:

@RestController
public class UserController {
	  @PostMapping("/post")
	  public User post(@RequestBody User user) {}
}

How do we use Feign to request? As follows:

@FeignClient(name = "user-service")
public interface UserFeignClient {
  @PostMapping("/post")
  public User post(@RequestBody User user);
}

7.Feign is used without Ribbon

How does Feign call a service that is not registered with the registry?
For example, I want to call Baidu: www.baidu.com com

//The name here must be written, or an error will be reported
@FeignClient(name = "baidu", url = "http://www.baidu.com")
public interface TestBaiduFeignClient {

    @GetMapping("")
    String index();
}

Other scenarios:
For example, if you want to call the HTTP interface of an external system, you can play like this.
Two examples:

  • You want to call Alipay's HTTP API;
  • Your Spring Cloud microservice wants to call the interface of the legacy project (the legacy project has not had time to reconstruct the Spring Cloud)

In short, Feign itself is an HTTP client. You can use Feign to send HTTP requests you want to send. Where do you want to request

8.RestTemplate VS Feign

angleRestTemplateFeign
Readability, maintainabilitycommonlyvery good
Development experiencePoorvery good
performancevery goodMedium (about 50% of RestTemplate)
flexibilityvery goodMedium (built-in function can meet most requirements)

How to choose?

Principle: use Feign as much as possible, avoid using RestTemplate, and choose reasonably

9. Feign's performance optimization

  • Connection pool (increased by about 15%)
    1.use apache httpclient Optimized
     Import dependency first:
    <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-httpclient</artifactId>
    </dependency>
    feign:
       httpclient:
    #     Let feign use apache httpclient to make requests; Instead of the default urlconnection
         enabled: true
    #     Maximum connections for feign
         max-connections: 200
    #     feign maximum number of connections for a single path
         max-connections-per-route: 50
         
    2.use okhttpclient optimization
     Similarly, the package is introduced to write configuration
    
  • Log level (set to BASIC)

Topics: Java Spring Spring Boot Distribution architecture