“This is the 14th day of my participation in the More Text Challenge. For more details, see more Text Challenge.”

What is OpenFeign

Feign is a declarative Web Service client. It is a declarative, template-based HTTP client. Spring Cloud supports Spring MVC annotations, such as @requesMapping, on the basis of Feign. OpenFeign’s @FeignClient can parse the interface under SpringMVC’s @RequestMapping annotation and use dynamic proxy to generate implementation classes that perform load balancing and invoke other services. Feign can hide Rest requests and pretend to be similar to SpringMVC’s Controller. You don’t have to concatenate urls, concatenate parameters, etc., all of that is done by Feign.

  1. Pluggable annotation support, including Feign annotations and JSX-RS annotations
  2. Support pluggable HTTP encoders and decoders
  3. Support for Hystrix and its Fallback
  4. Supports load balancing in the Ribbon
  5. Support for compression of HTTP requests and responses.

Introduction to OpenFeign

Create parent Pom project: cloud-Openfeign-Practice

This project is used to house all the openFeign examples.

pom.xml


      
<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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.msr.better</groupId>
    <artifactId>cloud-openfeign-practice</artifactId>
    <version>1.0</version>

    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.3. RELEASE</version>
        <relativePath/> <! -- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR3</spring.cloud-version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
Copy the code

Create the module: cloud-OpenFeign-HehlLO

pom.xml

	<dependencies>
        <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>
Copy the code

The configuration file

application.xml

server:
  port: 8010
spring:
  application:
    name: openfeign-hello
# log
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug

Copy the code

The configuration class

@Configuration
public class HelloFeignServiceConfig {

    /** * Logger.Level Specifies the following levels: * NONE: records no information * BASIC: records only the request method, URL, response status code, and execution time * HEADERS: In addition to BASIC level information, request and response header information is also recorded. * FULL: Records details of all requests and responses, including header information, request body, and metadata */
    @Bean
    Logger.Level feignLoggerLevel(a) {
        returnLogger.Level.FULL; }}Copy the code

serivce

@FeignClient(name = "github-client", url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {

    /**
     * content:
     * {
     *  "message":"Validation Failed",
     *  "errors":[{"resource":"Search","field":"q","code":"missing"}],
     *  "documentation_url":"https://developer.github.com/v3/search"
     *  }
     *
     * @param queryStr
     * @return* /
    @GetMapping(value = "/search/repositories")
    String searchRepo(@RequestParam("q") String queryStr);

}
Copy the code

In HelloFeignService above, the @feignClient annotation manually specifies the URL(api.github.com) to be accessed by the interface. When calling the searchGithubRepoByStr method, Eventually a GET request will be made https://api.github…

controller

@RestController
public class HelloFeignController {

    @Autowired
    private HelloFeignService helloFeignService;

    @GetMapping(value = "/search/github")
    public String searchGithubRepoByStr(@RequestParam("searchStr") String searchStr) {
        returnhelloFeignService.searchRepo(searchStr); }}Copy the code

Start the class

@SpringBootApplication
@EnableFeignClients
public class OpenFeignHelloApplication {

    public static void main(String[] args) { SpringApplication.run(OpenFeignHelloApplication.class, args); }}Copy the code

When the @enableFeignClients package is scanned, all @FeignClients are scanned.

Start the test

Run to start the class, in your browser or the PostMan tools like http://localhost:8010/search/github? searchStr=spring-cloud

How OpenFeign works

  • Add the @enableFeignClients annotation to enable scanning and loading of the @FeignClient annotation. According to the development specification of Feign Client, define the interface and add @Feiginclient annotation
  • When the program starts, a package scan is performed to scan all @FeignClient annotated interfaces and inject this information into the IOC container. When the defined Feign interface is called, a specific RequestTemplate is generated using the JDK’s proxy. Feign creates a RequestTemplate object for each interface method. This object encapsulates all the information required for an HTTP request, such as the request parameter name, request method, and so on.
  • The Request is then generated by the RequestTemplate and handed over to a Client, which can be a JDK native URLConnection, HttpClient, or Okhttp. Finally, the Client is encapsulated in the LoadBalanceClient class. The name of this class can be seen as a combination of the Ribbon load balancing to make calls between services. OpenFeign has the Ribbon integrated by default.

Basic functions of OpenFiegn

Parse @FeignClient annotations

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interfaceFeignClient {... }Copy the code

As you can see from the FeignClient annotation, elementType. TYPE indicates that the function of FeignClient is the interface. Its common attributes are as follows:

  • Name: The name of the execution FeignClient. If the Ribbon is used in a project, the name attribute is used as the name of the microservice, which is used for service discovery.
  • Url: Urls are generally used for debugging, and you can manually specify the address for @feignClient calls
  • Decode404: When a 404 error occurs, if this field is true, decoder is called to decode, otherwise FeignException is thrown.
  • Configuration: Feigin configuration class, you can customize Encode, Decode, LogLevel, Contract of Feign.
  • Fallback: Defines a fault-tolerant class that will invoke the fault-tolerant Roger of a remote interface when it fails or times out. Fallback classes must implement the @FeignClient flag. Found in OpenFeign’s dependencies, integrated with Hystrix.
  • FallbackFactory: Factory class used to generate instances of fallback classes. This property enables common fault-tolerant logic for each interface to reduce duplication of code.
  • Path: Defines the uniform prefix of the current FeignClient.

OpenFeign starts GZIP compression

OpenFeign supports GZIP compression of requests and responses to provide communication efficiency. You only need to configure it in the configuration file, which is relatively simple.

server:
  port: 8011
spring:
  application:
    name: openfeign-gzip
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug
feign:
  # Compression configuration
  compression:
    request:
      enabled: true
      # Configure the MIME TYPE supported by compression
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048  Configure a lower limit for the compressed data size
    response:
      enabled: true # Configure response GZIP compression

Copy the code

Equivalent properties configuration

feign.compression.request.enabled=true
# Configure the MIME TYPE supported by compression
feign.compression.request.mime-types=text/xml,application/xml,application/json
Configure a lower limit for the compressed data size
feign.compression.request.min-request-size=2048
# Configure response GZIP compression
feign.compression.response.enabled=true
Copy the code

Supports property file configuration

Configure a single FeignClient with a specific name

The configuration information for @feignClientde can be configured as a configuration file

server:
  port: 8011
spring:
  application:
    name: openfeign-gzip
logging:
  level:
    com.msr.better.feign.service.HelloFeignService: debug
feign:
  # Compression configuration
  compression:
    request:
      enabled: true
      # Configure the MIME TYPE supported by compression
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048  Configure a lower limit for the compressed data size
    response:
      enabled: true # Configure response GZIP compression
  client:
    config:
      # FeignName to be configured
      github-client:
        # Connection timeout
        connectTimout: 5000
        # Read timeout
        readTimeut: 5000
        # Feign log level
        loggerLevel: full
        # Feign error decoder
        errorDecode: com.example.SimpleErrorDecoder
        # Set retry
        retryer: com.example.SimpleRetryer
        # before
        requestInterceptors:
          - com.example.FirstInterceptor
          - com.example.SecondInterceptor
        decode404: false
        # Feign encoder
        encoder: com.example.SimpleEncoder
        # Feign decoder
        decoder: com.example.SimpleDecoder
        Contract configuration for # Feign
        contract: com.example.SimpleContract
Copy the code

This applies to all FeignClient configurations

Have a defaultConfiguration attribute in @ EnableFeignClients annotation, the default Settings can be written as a configuration class, such as the class is called DefaultFeignClientConfiguration.

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = DefaultFeignClientConfiguration.class)
public class FeignClientConfigApplication{
    SpringApplication.run(FeignClientConfigApplication.class, args);
}
Copy the code

You can also configure it in the configuration file

feign:
  client:
    config:
      default:
        # Connection timeout
        connectTimout: 5000
        # Read timeout
        readTimeut: 5000
        # Feign log level
        loggerLevel: full
        .
Copy the code

However, if you configure FeignClient’s global configuration both in the configuration file and in the annotations, the configuration file overrides the way the configuration class is executed on the annotations. However, you can change the priority of the Feigin configuration by adding feign.client.default-to-properties=false to the configuration file.

FeignClient enables logging

In fact, the above is already configured FeignClient logging. Feign provides an instance of Fegin.Logger for each Feign. It is easy to enable log output in the configuration.

Step 1: Configure log output in the configuration file

logging:
  level:
    # Specify which FeignClient interface requests need to output logs, and the log level
    com.msr.better.feign.service.HelloFeignService: debug
Copy the code

Step 2: Configure the log Bean in the main program entry using Java code


    @Bean
    Logger.Level feignLoggerLevel(a) {
        return Logger.Level.FULL;
    }
Copy the code

Alternatively, you can configure the class through the configuration class and perform the configuration class changes in the @FeignClient annotation.

@Configuration
public class HelloFeignServiceConfig {

    /** * Logger.Level Specifies the following levels: * NONE: records no information * BASIC: records only the request method, URL, response status code, and execution time * HEADERS: In addition to BASIC level information, request and response header information is also recorded. * FULL: Records details of all requests and responses, including header information, request body, and metadata */
    @Bean
    Logger.Level feignLoggerLevel(a) {
        returnLogger.Level.FULL; }}Copy the code

FeignClient timeout configuration

Feign calls are divided into two layers, the Ribbon calls and the Hystrix calls. However, higher versions of Hystrix are turned off by default. Read timed out executing POST http://*** is an exception caused by the Ribbon. In this case, the Ribbon can be properly timed out

ribbon:
  ConnectTimeout: 2000
  ReadTimeout: 5000
Copy the code

HystrixRuntimeException: XXX timed -out and no fallback available . This is the Hystrix timeout error

feign:
  hystrix:
    enabled: true
Set hystrix timeout
hystrix:
  shareSecurityContext: true
  command:
    default:
      circuitBreaker:
        sleepWindowinMilliseconds: 10000
        forceClosed: true
      execution:
        isolation:
          thread:
            timeoutinMilliseconds: 10000
Copy the code