1, the preface

The spirit ferryman Nacos in Spring Cloud, introduced earlier, is not only powerful compared to its predecessors, but also very simple to deploy.

Today we introduce a service invocation component: OpenFeign, which is also a tough player beyond the Ribbon and Feign.

The table of contents is as follows:

2. What is Feign?

Feign is also a tough player. Feign aims to make Java Http clients easier.

Feign integrates Ribbon and RestTemplate to implement load-balancing Http calls. The Ribbon+RestTemplate approach is packaged. Developers do not need to manually use RestTemplate to call services, but define an interface. The service invocation can be done with a single annotation in this interface, which is more in line with the purpose of interface oriented programming and simplifies development.

Unfortunately, Feign has stopped iterating, and of course many enterprises are using it now.

If you want to learn Feign, you can go to the official website of Spring Cloud to learn it. Chen won’t introduce it in detail here, so it’s not the focus of today.

3. What is openFeign?

The Feign that stops iterating was introduced earlier, but to put it simply: OpenFeign is springCloud’s annotation that supports SpringMVC on top of Feign, like @requestMapping and so on. OpenFeign’s @FeignClient can parse the interface under SpringMVC’s @RequestMapping annotation and generate implementation classes through dynamic proxy, which can perform load balancing and call other services.

IO/Spring-clou…

What’s the difference between Feign and openFeign?

Feign openFiegn
Feign is a lightweight RESTful HTTP service client in The SpringCloud component. Feign has a built-in Ribbon for client load balancing and invoking services in the service registry. Feign is used by using Feign’s annotations to define an interface that can be invoked to invoke the services of the service registry OpenFeign is a SpringCloud annotation that supports SpringMVC on top of Feign, such as @requestMapping, etc. OpenFeign’s @FeignClient can parse the interface under SpringMVC’s @RequestMapping annotation and generate implementation classes through dynamic proxy, which can perform load balancing and call other services.

5. Environmental preparation

The Spring Cloud version, JDK environment, and project environment of this article are the same as those of the previous Nacos article: 55 diagrams to tell you just how strong Nacos is, the soul ferrier of microservices. .

The registry will no longer use Eureka and will use Nacos as the registration and configuration center. If not, check out the Nacos article.

The project structure of this article is as follows:

The registry uses Nacos to create microservices, namely service provider Produce and service Consumer.

6. Create a service provider

Create OpenFeign-Provider9005, register in Nacos, and configure as follows:

server:
  port: 9005
spring:
  application:
    Specify the service name, the name in nacOS
    name: openFeign-provider
  cloud:
    nacos:
      discovery:
        The IP address in nacOS-server is the port number
        server-addr: 127.0. 01.: 8848
management:
  endpoints:
    web:
      exposure:
        Special characters exist in the ## yML file and must be enclosed in single quotation marks; otherwise, an error will be reported during startup
        include: The '*'
Copy the code

Note: The name specified here in Spring.application. name will be used in the openFeign interface call.

Project source code will be uploaded, about how to register into Nacos, add any dependent source code will have, combined with Chen’s last Nacos article, this is not difficult!

7. Create service consumers

To create a new module openFeign-Consumer9006 as a consumer service, do the following.

1. Add dependencies

In addition to Nacos registry dependencies, add openFeign dependencies as follows:

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

2. Add @enableFeignClients to enable openFeign

Add a @enableFeignClients annotation to the main Spring Boot class to enable openFeign:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OpenFeignConsumer9006Application
{
    public static void main(String[] args) { SpringApplication.run(OpenFeignConsumer9006Application.class, args); }}Copy the code

3. Create an openFeign interface

Create a new openFeign interface annotated with the @FeignClient annotation as follows:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {}Copy the code

Note: The value attribute in the @feignClient annotation specifies the service name of the service provider in the NACOS registry.

4. Create a new Controller debug

Create a new controller to debug the interface and call the openFeign interface directly as follows:

@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {}Copy the code

Ok, now an openFeign microservice is set up. It does not implement specific functions.

8. How to pass openFeign parameters?

There are many ways of interface parameter passing in development, but there are certain rules for parameter passing in openFeign, which are described below.

1. Pass JSON data

This is also a common parameter passing rule in interface development, and is entered in Spring Boot with the @requestBody identifier.

The method for transferring JSON parameters on the Provider interface is as follows:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/order2")
    public Order createOrder2(@RequestBody Order order){
        returnorder; }}Copy the code

The code for passing parameters in the openFeign interface of Consumer is as follows:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /** * The default value is@RequestBodyIt's labeled here@RequestBodyThe method name can be left blank with any */
    @PostMapping("/openfeign/provider/order2")
    Order createOrder2(@RequestBody Order order);
}
Copy the code

Note: openFeign’s default way of passing parameters is JSON (@requestBody), so you can define the interface without the @RequestBody annotation, but for the sake of specification, it is usually filled in.

2. Pass POJO form parameters

This method of parameter passing is also common, and parameters are received using POJO objects.

Provider The code of the service provider is as follows:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/order1")
    public Order createOrder1(Order order){
        returnorder; }}Copy the code

The code for Consumer openFeign is as follows:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /** * The default value is@RequestBodyAnnotated, if passed through the POJO form, use@SpringQueryMapMarked with * /
    @PostMapping("/openfeign/provider/order1")
    Order createOrder1(@SpringQueryMap Order order);
}
Copy the code

Many people on the Internet are confused about how to pass the POJO form. The official document clearly provides the solution as follows:

OpenFeign provides an annotation @SpringQueryMap that perfectly solves POJO form pass-through.

3. The URL carries parameters

This mode is common for RESTFUL GET requests.

Provider The code of the service provider is as follows:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {

    @GetMapping("/test/{id}")
    public String test(@PathVariable("id")Integer id){
        return "accept one msg id="+id;
}
Copy the code

The Consumer openFeign interface is as follows:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {

    @GetMapping("/openfeign/provider/test/{id}")
    String get(@PathVariable("id")Integer id);
}
Copy the code

It makes sense to use the annotation @pathVariable to receive placeholders in the URL.

4. Common form parameters

This method of parameter passing is not recommended, but there are many developments in use.

Provider The code of the service provider is as follows:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/test2")
    public String test2(String id,String name){
        return MessageFormat.format(Accept on MSG id={0}, name={1}",id,name); }}Copy the code

Consumer openFeign interface parameters are as follows:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /** * required@RequestParamAnnotation annotation, and the value property must be filled with the parameter name * method parameter name can be arbitrary, but@RequestParamThe value attribute in the annotation must be the same as the parameter name in the provider */
    @PostMapping("/openfeign/provider/test2")
    String test(@RequestParam("id") String arg1,@RequestParam("name") String arg2);
}

Copy the code

5, summary

There are many ways to pass parameters, for example,….. Chen here just listed four common ways to pass the reference.

9. How to handle timeout?

To understand timeout handling, consider an example: I sleep the Provider service interface for three seconds as follows:

@PostMapping("/test2")
public String test2(String id,String name) throws InterruptedException {
        Thread.sleep(3000);
        return MessageFormat.format(Accept on MSG id={0}, name={1}",id,name);
}
Copy the code

At this point, we call consumer’s openFeign interface and return the following result:

It is clear that the program is abnormal and returns an interface call timeout. What? According to? .

OpenFeign has a default connection timeout of 10 seconds, and a read timeout of 60 seconds.

Which begs the question: Why did I clock out after only three seconds?

In fact, openFeign integrates the Ribbon. The Ribbon’s default connection timeout and read timeout are both 1 second. Source in the org. Springframework. Cloud. Openfeign. Ribbon. FeignLoadBalancer# the execute () method, the diagram below:

If openFeign does not set the Ribbon’s default timeout, the Ribbon’s default timeout will be used.

Having understood the principle of timeout setting, it is also clear that there are two schemes arising from it, as follows:

  • Set the openFeign timeout period
  • Set the Ribbon timeout

1. Set the Ribbon timeout (not recommended)

Setup is simple, add the following Settings to the configuration file:

ribbon:
  The # value is the time it takes to establish a link, which applies to the time it takes to establish a link between two ends under normal network conditions
  ReadTimeout: 5000
  # refers to the time it takes to read the available resources from the server after the link is established
  ConectTimeout: 5000
Copy the code

2. Set openFeign timeout (recommended)

OpenFeign is very simple to set the timeout, just need to configure in the configuration file, as follows:

feign:
  client:
    config:
      ## default Specifies the global timeout period. You can set the timeout period for a single service by specifying the service name
      default:
        connectTimeout: 5000
        readTimeout: 5000
Copy the code

Default sets the global timeout period, which applies to all openFeign interface services

However, normal business logic may involve multiple openFeign interface calls, as shown in the following figure:

The pseudocode in the figure above is as follows:

public T invoke(a){
    / / 1. Call serviceA
    serviceA();
    
    / / 2. Call serviceA
    serviceB();
    
    / / 3. Call serviceA
    serviceC();
}
Copy the code

Does the global timeout set above pass? ServiceA and serviceB can be successfully called, but serviceC cannot be successfully executed.

In this case, you can configure a timeout period for the serviceC service as follows:

feign:
  client:
    config:
      ## default Specifies the global timeout period. You can set the timeout period for a single service by specifying the service name
      default:
        connectTimeout: 5000
        readTimeout: 5000
      Configure a separate timeout for the serviceC service
      serviceC:
        connectTimeout: 30000
        readTimeout: 30000
Copy the code

Note: the timeout for a single configuration overrides the global configuration.

10. How do I enable log enhancement?

OpenFeign provides logging enhancements, but does not display any logs by default, although developers can configure their own logging levels during debugging.

The log levels of openFeign are as follows:

  • NONE: By default, no logs are displayed.
  • BASIC: only request method, URL, response status code and execution time are recorded;
  • HEADERS: Request and response HEADERS in addition to the information defined in BASIC;
  • FULL: In addition to the information defined in HEADERS, there is the body and metadata of the request and response.

It is also easy to configure. The steps are as follows:

1. Configure the log level in the configuration class

You need to customize a configuration class to set the log level as follows:

Note: The logger here is in the Feign package.

2. Set the interface log level in the YAML file

You only need to adjust the log level of the specified package or openFeign interface in the configuration file as follows:

logging:
  level:
    cn.myjszl.service: debug
Copy the code

In this case, cn.myjszl.service is the package name of the openFeign interface, although you can also configure a specific openFeign interface.

3. Demo effect

The above steps set the log to FULL, then send the request, and the log effect is as follows:

The log displays the request header and request body in detail.

How to replace the default HttpClient?

Feign uses the JDK’s native URLConnection to send HTTP requests by default. There is no connection pool, but it maintains a long connection to each address using HTTP’s persistence Connection.

In a production environment, you usually do not use the default HTTP client. There are two options:

  • Using ApacheHttpClient
  • Using OkHttp

As for which is better, in fact, different, I prefer ApacheHttpClient, after all, the old brand, stability is not a problem.

So how do you replace it? In fact, it is very simple, the following demonstration using ApacheHttpClient replacement.

Add ApacheHttpClient dependencies

Add the following dependencies to the openFeign interface service poM file:

<! Apache HttpClient instead of Feign native HttpClient -->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
    </dependency>
    
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-httpclient</artifactId>
    </dependency>
Copy the code

Why add the above dependencies? It is not hard to see from the source, please see org. Springframework. Cloud. Openfeign. FeignAutoConfiguration. HttpClientFeignConfiguration this class, the code is as follows:

Conditioncondition@conditionAlonClass (apacheHttpClient.class) is conditional on the ApacheHttpClient class. And feign.httpClient. enabled should be set to true.

2. Enable it in the configuration file

To enable the configuration in the configuration file, the code is as follows:

feign:
  client:
    httpclient:
      # Enable Http Client
      enabled: true
Copy the code

3. How to verify that the replacement is successful?

. Actually very simple, in feign SynchronousMethodHandler# executeAndDecode () this method can clearly see that calls in which the client, the following figure:

You can see in the figure above that the ApacheHttpClient is finally called.

4, summarize

The above steps demonstrate only one alternative, the remaining one is not demonstrated, and the principle is the same.

12. How to optimize communication?

Before we talk about how to optimize, let’s take a look at the GZIP compression algorithm. The concept is as follows:

Gzip is a data format that uses deflate to compress data; Gzip is a popular data compression algorithm that is widely used, especially on Linux platforms.

When GZIP is compressed to a plain text data, the effect is dramatic, reducing the data size by more than 70%.

Compressed network data actually reduces the number of bytes transmitted over the network, with the most obvious benefit being faster web page loading. In addition to saving traffic and improving the user’s browsing experience, another potential benefit is that GZIP has a better relationship with search engine scraping tools. Google, for example, can retrieve web pages faster than normal manual crawling by reading GZIP files directly.

The principle of GZIP compression and transmission is shown as follows:

The steps of disassembly are as follows:

  • The client requests the server with:Accept-Encoding:gzip,deflateField indicating to the server that the client supports the compression format (gzip or Deflate). The server will not compress the header if it is not sent.
  • After receiving a request, the server finds that the request header containsAccept-EncodingField, and supports this type of compression, the response packet is compressed and returned to the client, and carriedContent-Encoding:gzipMessage header: indicates that the response packet is compressed according to the format.
  • After receiving the response, the client checks whether the content-Encoding header exists. If so, it decompresses the packet in this format. Otherwise, normal packets are processed.

OpenFeign supports request/response to enable GZIP compression. The overall process is shown as follows:

Application Client ->Application Service and Application Service->Application Client.

Note: openFeign supports GZIP only for requests and responses in the openFeign interface, which is the openFeign consumer’s interface to invoke the service provider.

OpenFeign to enable GZIP is also very simple, just need to enable the following configuration in the configuration file:

feign:
  ## Enable compression
  compression:
    request:
      enabled: true
      ## Enable compression threshold in bytes, default 2048, i.e. 2k, set to 10 bytes for demonstration purposes
      min-request-size: 10
      mime-types: text/xml,application/xml,application/json
    response:
      enabled: true
Copy the code

After the above configuration is complete, the request is issued and you can clearly see that the request header already carries GZIP compression as shown below:

13. How to fuse downgrade?

Hystrix and Sentinel are common fuse downgrading frameworks. OpenFeign supports Hystrix by default, which is shown in the official documentation. After all, we are the same people, haha………..

However, Ali’s Sentinel completely beats Hystrix in functions and features, simplicity and accessibility, so this chapter uses openFeign+Sentinel to achieve service degradation.

Note: Sentinel is not highlighted here, Chen plans to introduce Sentinel in detail in his next article.

1. Add Sentinel dependencies

Add a sentinel dependency to the PoM file of the OpenFeign-Consumer9006 consumer (no version number specified due to the aggregation module used) as follows:

<dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
Copy the code

2. Enable Sentinel fuse downgrade in the configuration file

In order for openFeign to use Sentinel’s degrade feature, you also need to turn it on in the configuration file and add the following configuration:

feign:
  sentinel:
    enabled: true
Copy the code

3. Add a degrade callback class

This class must implement the same class as the openFeign interface, as shown below:

OpenFeignFallbackService is a callback class that will be called to degrade an owed method if an exception occurs on the owed interface in OpenFeignService.

4. Add the fallback attribute

Add the fallback property to @feignClient with the value of the degraded callback class as follows:

@FeignClient(value = "openFeign-provider",fallback = OpenFeignFallbackService.class)
public interface OpenFeignService {}
Copy the code

5, presentations,

After the four steps above, openFeign’s fusing downgrade is set up. Here’s how it works.

Through the postman calls http://localhost:9006/openfeign/order3 this interface, normal logic to return to the diagram below:

Now manually create an exception and throw it in the interface provided by the service, as shown below:

At this point to call http://localhost:9006/openfeign/order3, return to the diagram below:

Oh huo, you can clearly see that the service has successfully degraded the call, oh, the function is complete.

Note: in the actual development of the return results should be customized according to the architecture, Chen here is just for the convenience of demonstration, do not use for reference, haha…

14,

This article is mainly for beginners, in-depth source code and fuse downgrade in the back of the detailed introduction, if there is unclear, the wrong place welcome correction!

This is the second article of Chen’s Spring Cloud advanced column. If you think the article is good, please like it, collect it and forward it.

The above source code has been uploaded to GitHub, the public number needed [code monkey technology column] reply keywords 9528 to obtain.