How Feign works

  • The @enableFeignClients annotation is added to the main program entry to enable the FeignClient scan loading process. Define the interface and annotate it with @FeignClientd according to the FeignClient development specification.

  • When the program starts, it does a package scan, scans all @FeignClients annotated classes, and injects this information into the Spring IOC container. When the Feign interface methods defined are called, the JDK proxy generates a specific RequestTemplate. When the proxy is generated, Feign creates a RequestTemplate for each interface method. When generating a proxy, Feign creates a RequestTemplate object for each interface method, which encapsulates all the information needed to make HTTP requests, such as request parameter names, request methods, and so on.

  • RequestTemplate then generates the Request and sends it to the Client to process. The Client can use JDK native URLConnection,Apache HttpClient, or OKhttp. Finally, the Client is packaged into the LoadBalanceClient class, which uses the Ribbon to load balance calls between generator services.

Feign annotation analysis

The @feignClient annotation is primarily decorated by @target ({elementtype.type}) to indicate that the annotation is primarily used on the interface. It has the following properties:

  • Name: Specifies the name of FeignClient. If the Ribbon is used, name is used as the name of the microservice for service discovery.

  • Url: THE URL is used for debugging. You can specify the address of the @feignClient call.

  • Decode404: When a 404 error occurs, if the field is true, decoder will be called for decoding, otherwise FeignException will be thrown.

  • Configuration :Feign configuration class, you can customize or configure Feign Encoder, Decoder, LogLevel, Contract.

  • Fallback: Defines a fault-tolerant processing class. When the remote interface fails to be called or times out, the fault-tolerant logic of the corresponding interface will be called. The class specified by fallback must implement the @feign interface.

  • FallbacjFactory: Factory class used to generate fallback class instances. This property implements fault tolerant logic common to each interface.

  • Path: defines the unified prefix of the current FeignClient.

Feign Enables GZIP compression

Spring Cloud Feign supports GZIP compression of requests and responses to improve communication efficiency. The following configuration is required in the YML file

Feign: compression: request: enabled: true # mimeTypes: # media type text/XML, application/XML, application/json minRequestSize: 2048 # the smallest size request response: enabled: true # on the compression of responseCopy the code

ResponseEntity<byte[]> is the ResponseEntity<byte[]> ResponseEntity<byte[]>.

@FeignClient(name = "github-client",url = "https://api.github.com",configuration = HelloFeignServiceConfig.class) public Interface HelloFeignService {/* This return type is binary if compressed, ResponseEntity< bytes []> */ @requestMapping (value = "/search/repositories",method = requestmethod.get) ResponseEntity<byte[]> searchRepositories(@RequestParam("q")String parameter); }Copy the code

Feign Client enables logging

Class that needs to add configuration to the annotation class:

@FeignClient(name = "github-client",url = "https://api.github.com",configuration = HelloFeignServiceConfig.class)
Copy the code

The code for the annotation class looks like this:

@configuration public class HelloFeignServiceConfig {/** ** logger. Level Specifies the following levels: NONE: no information is recorded. Only request method, URL, response status code, and execution time are recorded. HEADERS: In addition to BASIC level information, request and response HEADERS are recorded. * @return */ @bean Loggerlevel feignLoggerLevel() {return logger.level.full; }}Copy the code

Feign timeout setting

Feign calls are made in two layers, the Ribbon layer and Hystrix, with higher versions of Hystrix turned off by default.

  • If the above error occurs, the following configuration needs to be added

    # the timeout request processing ribbon. ReadTimeout: 12000 # link request timeout ribbon. The ConnectionTimeout: 30000

  • If Hystrix is enabled, the Hystrix timeout message is as follows:

You can add the following configuration:

hystrix:
  command:
    default:
      circuitBreaker:
        sleepWindowInMilliseconds: 30000
        requestVolumeThreshold: 50
      execution:
        timeout:
          enabled: true
        isolation:
          strategy: SEMAPHORE
          semaphore:
            maxConcurrentRequests: 50
          thread:
            timeoutInMilliseconds: 100000
Copy the code

Feign multi-parameter Post and Get pass

In SpringMVC, you can easily use Post or Get requests to request the corresponding interface and bind parameters to a POJO. However, Feign does not fully implement SpringMVC functions. If you use Get requests to the interface, you cannot bind parameters to a POJO. However, there are several ways to implement this functionality.

  • Unload the fields in the POJO as fields on the interface

  • Program the parameters into a map

  • Pojos use the @requestBody modifier, but this violates Restful principles

The following code intercepts Feign’s request and processes the parameters to create a unified programming map

@Component public class FeignRequestInterceptor implements RequestInterceptor{ @Autowired private ObjectMapper objectMapper; @override public void apply(RequestTemplate RequestTemplate) { Query if (requestTemplate.method().equalsIgnoRecase ("GET") &&requestTemplate.body ()! =null){ try { JsonNode jsonNode = objectMapper.readTree(requestTemplate.body()); requestTemplate.body(null); Map<String,Collection<String>> queries = new HashMap<>(); buildQuery(jsonNode,"",queries); requestTemplate.queries(queries); } catch (IOException e) { e.printStackTrace(); } } } private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) { if (! Jsonnode.iscontainernode ()) {if (jsonNode.isnull ()) {return; } Collection<String> values = queries.get(path); if (null == values) { values = new ArrayList<>(); queries.put(path, values); } values.add(jsonNode.asText()); return; } if (jsonNode.isarray ()) {Iterator< jsonNode > it = jsonNode.elements(); while (it.hasNext()) { buildQuery(it.next(), path, queries); } } else { Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields(); while (it.hasNext()) { Map.Entry<String, JsonNode> entry = it.next(); if (StringUtils.hasText(path)) { buildQuery(entry.getValue(), path + "." + entry.getKey(), queries); } else {// Root buildQuery(entry.getValue(), entry.getKey(), queries); } } } } }Copy the code

In addition to the above method, you can also use the Venus-cloud-feign dependency, which implements the Map wrapper for the parameters of the GET request without having to write them yourself. Dependencies are as follows:

<! -- https://mvnrepository.com/artifact/cn.springcloud.feign/venus-cloud-feign-core --> <dependency> < the groupId > cn. Springcloud. Feign < / groupId > < artifactId > Venus - the cloud - feign - core < / artifactId > < version > 1.0.0 < / version > </dependency>Copy the code

Github’s address is github.com/SpringCloud…