The fastest shortcut in the world is to keep your feet on the ground. Focus on the sharing place.

Finchley.SR2

What is Feign

Feign is a declarative Web client that can create interfaces using its annotations and also supports custom codecs. Spring Cloud integrates Ribbon and Eureka to provide load balancing policies for clients. Feing has two main annotations: @enableFeignClients for enabling feIGN functionality and @FeignClient for defining the FEIGN interface.

Introduce Feign

1. Increase dependency

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

2, Example spring Boot app

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

StoreClient.java

@FeignClient("stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}
Copy the code

In the @feignClient annotation this (“stores”) parameter is a unique name (which is usually the service name) used to create the Ribbon’s load balancer. You can also use url parameters on annotations (find an absolute path, such as www.xxx.com).. The Ribbon client will find physical addresses based on (“stores”), find services in its registry if Eureka is used, and configure an external list if not.

Override the default Feign properties

Feign components as long as be @ FeignClient statement is a client, we can through the use of FeignClientsConfiguration create our custom configuration items, Decoder, a feign.Encoder, and a feign.contract.example

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
   //..
}
Copy the code

In this demo client comprised FeignClientsConfiguration and FooConfiguration two combination (configuration will cover at the front of the back)

The FooConfiguration class does not require the @Configuration annotation. If you add this you also need to exclude it when you use @ComponentScan. Otherwise it will be feign.decoder, feign.encoder, feign.contract default.

Note that the serviceId attribute in @feignClient is deprecated.

You didn't need to configure the name attribute to use urls in @feignClient before, now you must.

You can use placeholders on the URL and name properties of @FeignClient

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
   //..
}
Copy the code

Spring Cloud provides some default classes for Feign

  • Decoder feignDecoder: ResponseEntityDecoder (which wraps a SpringDecoder)
  • Encoder feignEncoder: SpringEncoder
  • Logger feignLogger: Slf4jLogger
  • Contract feignContract: SpringMvcContract
  • Feign.Builder feignBuilder: HystrixFeign.Builder
  • ClientFeignClient: If the Ribbon is enabledLoadBalancerFeignClientIf not enabled, use the default.

The following classes are not provided by default, but will be used when creating the client

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection<RequestInterceptor>
  • SetterFactory

As in the previous demo, create a class and use @feignClient to configure its configuration (such as this FooConfiguration), Example

@Configuration public class FooConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); }}Copy the code

The above configuration replaces SpringMvcContract with feign.contract.default and adds an interceptor. You can also configure @feignClient using a configuration file as follows:

application.yml

eign:
  client:
    config:
      feignName:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: full
        errorDecoder: com.example.SimpleErrorDecoder
        retryer: com.example.SimpleRetryer
        requestInterceptors:
          - com.example.FooRequestInterceptor
          - com.example.BarRequestInterceptor
        decode404: false
        encoder: com.example.SimpleEncoder
        decoder: com.example.SimpleDecoder
        contract: com.example.SimpleContract
Copy the code

Of course, this configuration class can also be placed in the @enableFeignClients property, but if it is configured that way, all clients are in effect. If you want to configure all @feignClients, you can use the default feign name as follows:

application.yml

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
Copy the code

If we create a configuration file as well as a configuration class, the configuration file has the highest priority and will override the properties of the configuration class. You can change this feature with feign.client.default-to-properties=false.

If you need to use the ThreadLocal binding parameter, you need to set Hystrix Isolation to SEMAPHORE

# To disable Hystrix in Feign
feign:
  hystrix:
    enabled: false

# To set thread isolation to SEMAPHORE
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE
Copy the code

Create Feign client manually

In some cases the above configuration does not work for your client, then use the Feign Builder API. To manually create a client. You can use different interceptors when you create them.

@Import(FeignClientsConfiguration.class) class FooController { private FooClient fooClient; private FooClient adminClient; @Autowired public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) { this.fooClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("user", "user")) .target(FooClient.class, "http://PROD-SVC"); this.adminClient = Feign.builder().client(client) .encoder(encoder) .decoder(decoder) .contract(contract) .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin")) .target(FooClient.class, "http://PROD-SVC"); }}Copy the code

FeignClientsConfiguration cloud is the default configuration, the PROD – SVC is the service name. Contract uses the injected default.

Feign Hystrix Fallbacks

Concept of demotion: When code execution fails or a demotion policy is enabled, a fallback attribute can be set at @feignClient to implement this demotion policy.

@FeignClient(name = "hello", fallback = HystrixClientFallback.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } static class HystrixClientFallback implements HystrixClient { @Override public Hello iFailSometimes() { return new Hello("fallback"); }}Copy the code

If you want to know the reason for the downgrade, configure the fallbackFactory property at @feignClient

FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class) protected interface HystrixClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") Hello iFailSometimes(); } @Component static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> { @Override public HystrixClient create(Throwable cause) { return new HystrixClient() { @Override public Hello iFailSometimes() { return new Hello("fallback; reason was: " + cause.getMessage()); }}; }}Copy the code

The demo above briefly explains how to implement demotion. But now downgraded strategy does not support method to return com.net flix. Hystrix. HystrixCommand and rx. Observables.

Feign and @primary

When using the degrade policy in Feign Hystrix, if an instance of the same type is in ApplicationContext. An error is reported when using @autowired injection and the @primary annotation must be used. To run properly, Spring Cloud annotates all Feign instances with the @primary annotation. There are cases where this can be problematic, so there is a way to turn it off by setting the @feignClient property primary to false.

FeignClient(name = "hello", primary = false)
public interface HelloClient {
	// methods here
}
Copy the code

Feign Request/Response compression

Can open the request/response GZIP compression function, configuration properties for feign.com pression. Request. Enabled = true feign.com pression. Response. Enabled = true

There are also several web server configuration feign.com pression. Request, enabled = true feign.compression.request.mime-types=text/xml,application/xml,application/json feign.compression.request.min-request-size=2048

Eight, Feign logging

You can use the fully qualified class called Feing Client to create a recorder, recorder level DEBUG logging. Level. Project. User. UserClient: can the DEBUG configuration Logger. The level to set up the how to print log

BASIC records only the request method and URL, the response status code and the execution time HEADERS, and records BASIC information and the request and response HEADERS. FULL, a header file that records requests and responses, body, and metadata

@Configuration public class FooConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }}Copy the code