Feign FAQ summary

If the FeignClient interface uses @pathVariable, it must specify the value attribute

// In some earlier versions, the "id", or value attribute, in @pathVariable ("id") must be specified and cannot be omitted. @FeignClient("microservice-provider-user") public interface UserFeignClient { @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET) public User findById(@PathVariable("id") Long id); . }Copy the code

Java code to customize Feign Client’s attention points and pits

@FeignClient(name = "microservice-provider-user", configuration = UserFeignConfig.class) public interface UserFeignClient { @GetMapping("/users/{id}") User findById(@PathVariable("id") Long id); } /** * The Feign Client configuration class, note: * 1. This class can be isolated; * 2. You can add @Configuration to this class as a Configuration class. * The @Configuration annotation can also be added to the Configuration class to declare it to be a Configuration class. * But don't place this in a package scanned by the main application context @ComponentScan at this time, * otherwise, the configuration will be shared by all Feign Clients, making fine-grained configuration impossible! * Personal advice: Like me, * * @author zhouli */ class UserFeignConfig {@bean public logger. Level Logger () {return Logger.Level.FULL; }}Copy the code
  • You can also add an @configuraiton annotation to the configuration class to declare it to be a configuration class. Don’t place it in a package that the main application context @ComponentScan scans. Otherwise, the configuration will be shared by all Feign Clients. Fine grained configuration is not possible!
  • Personal advice: Do what I did, and leave @Configuration out of it.
  • Best practice: Customize Feign configurations with configuration attributes whenever possible!!

@feignClient Annotation property

// @feignClient (name = "microservice-provider-user") // In earlier Spring Cloud releases, there was no need to provide the name attribute. Starting with Brixton, @feignClient must provide the name attribute. Otherwise, the application will not start properly! // In addition, properties such as name and URL support placeholders. For example: @feignClient (name = "${feign.name}", url = "${feign.url}")Copy the code

Class level @RequestMapping is loaded by Spring MVC

@RequestMapping("/users")
@FeignClient(name = "microservice-user")
public class TestFeignClient {
    // ...
}Copy the code

The @requestMapping annotation on the class is also loaded by Spring MVC. This issue has now been resolved, and in earlier versions there were two solutions: Option 1: not add @requestMapping annotations to the class; Option 2: Add the following code:

@Configuration @ConditionalOnClass({ Feign.class }) public class FeignMappingDefaultConfiguration { @Bean public WebMvcRegistrations feignWebRegistrations() { return new WebMvcRegistrationsAdapter() { @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return new FeignFilterRequestMappingHandlerMapping(); }}; } private static class FeignFilterRequestMappingHandlerMapping extends RequestMappingHandlerMapping { @Override protected boolean isHandler(Class<? > beanType) { return super.isHandler(beanType) && ! beanType.isInterface(); }}}Copy the code

The first failed request the agent-load mode of the Ribbon

To generate Hystrix Stream monitoring information, you need to do something extra. Feign already integrates Hystrix itself, @feignClient (value = “microservice-provider-user”, fallback = xxx.class) The Fallback class inherits the interface annotated by @FeignClient.

But suppose if you want to use Hystrix Stream monitor, by default, http://IP:PORT/actuator/hystrix.stream will return 404, although this is because the Feign integrates Hystrix, But it doesn’t integrate Hystrix’s surveillance. How do you add monitoring support? The following steps are required:

Step 1: Add a dependency. Example:

<! -- Hystrix integration, which comes with Hystrix in Feign, was introduced to use hystrix-metrics-event-stream. Used in the dashboard - > < the dependency > < groupId > org. Springframework. Cloud < / groupId > <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>Copy the code

Step 2: Add the @enablecircuitbreaker annotation to the startup class, as in:

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

Step 3: Expose the Hystrix.stream endpoint by adding the following to application.yml:

management:
  endpoints:
    web:
      exposure:
        include: 'hystrix.stream'Copy the code

In this way, access to any Feign Client interface API, visit http://IP:PORT/actuator/hystrix.stream again, will show a lot of Hystrix monitoring data.

The original link: http://www.itmuch.com/spring-cloud-sum/feign-problems/

Feign uploads files

And rely on

< the dependency > < groupId > IO. Making. Openfeign. Form < / groupId > < artifactId > feign - form < / artifactId > < version > 3.0.3 < / version > </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> The < version > 3.0.3 < / version > < / dependency >Copy the code

Write Feign Client

@FeignClient(name = "ms-content-sample", configuration = UploadFeignClient.MultipartSupportConfig.class) public interface UploadFeignClient { @RequestMapping(value = "/upload", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody String handleFileUpload(@RequestPart(value = "file") MultipartFile file); class MultipartSupportConfig { @Bean public Encoder feignFormEncoder() { return new SpringFormEncoder(); }}}Copy the code

As shown in the code, in this Feign Client, we refer to the configuration class MultipartSupportConfig, where we instantiate SpringFormEncoder. So the Feign Client can upload.

Pay attention to the point

//RequestMapping注解中的produeces 、consumes 不能少;
@RequestMapping(value = "/upload", method = RequestMethod.POST,
            produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)Copy the code
  • Annotations in the interface definition@RequestPart(value = "file")Can not write@ RequestParam (value = "file")
  • You are advised to set Hystrix timeout to a longer time, such as 5 seconds. Otherwise, Hystrix may time out before the file is uploaded, resulting in an error on the client.

The original link: http://www.itmuch.com/spring-cloud-sum/spring-cloud-feign-upload/

Feign implements Form submission

Add dependencies:

< the dependency > < groupId > IO. Making. Openfeign. Form < / groupId > < artifactId > feign - form < / artifactId > < version > 3.2.2 < / version > </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> The < version > 3.2.2 < / version > < / dependency >Copy the code

Feign Client example:

@FeignClient(name = "xxx", url = "http://www.itmuch.com/", configuration = TestFeignClient.FormSupportConfig.class) public interface TestFeignClient { @PostMapping(value = "/test", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE}, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE} ) void post(Map<String, ?> queryParam); class FormSupportConfig { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; // Create a form encoder. Implementation supports form submission @bean public Encoder feignFormEncoder() {return new SpringFormEncoder(new) SpringEncoder(messageConverters)); } @bean public logger.level Logger () {return logger.level.full; }}}Copy the code

Call example:

@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
  HashMap<String, String> param = Maps.newHashMap();
  param.put("username","zhangsan");
  param.put("password","pwd");
  this.testFeignClient.post(param);
  return new User();
}Copy the code

Log:

. [TestFeignClient# post] - > post http://www.baidu.com/test HTTP / 1.1... [TestFeignClient#post] Accept: application/json; charset=UTF-8 ... [TestFeignClient#post] Content-Type: application/x-www-form-urlencoded; charset=UTF-8 ... [TestFeignClient#post] Content-Length: 30 ... [TestFeignClient#post] ... [TestFeignClient#post] password=pwd&username=zhangsan ... [TestFeignClient#post] ---> END HTTP (30-byte body)Copy the code

According to the log, Feign can submit data using the Form Form.

The original link: http://www.itmuch.com/spring-cloud-sum/feign-form-params/

How do Feign GET requests construct multiple parameters

Suppose the URL to be requested contains multiple parameters, such as http://microservice-provider-user/get? Id =1&username= 1; We know that Spring Cloud adds Spring MVC annotation support to Feign, so let’s try it out with Spring MVC:

@FeignClient("microservice-provider-user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get0(User user);
}Copy the code

However, this is not written correctly, and the console prints an exception similar to the following.

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"}Copy the code

As you can see from the exception, Feign uses the POST method to send the request even though we specified the GET method. And that leads to an anomaly. The correct way to write it is as follows

Note: Fegin’s inheritance pattern cannot be used with this method

@FeignClient("microservice-provider-user")
public interface UserFeignClient {
  @GetMapping("/get")
  public User get0(@SpringQueryMap User user);
}Copy the code

Method 2 [Recommendation]

@FeignClient(name = "microservice-provider-user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get1(@RequestParam("id") Long id, @RequestParam("username") String username);
}Copy the code

This is the most intuitive way, urls have several parameters, and methods in the Feign interface have several parameters. Use the @requestParam annotation to specify what the parameters of the request are.

Method 3 [not recommended] Multi-parameter urls can also be constructed using a Map. This can be used to simplify Feign interface writing when the target URL parameters are very large.

@FeignClient(name = "microservice-provider-user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get2(@RequestParam Map<String, Object> map);
}Copy the code

When invoked, code similar to the following can be used.

public User get(String username, String password) { HashMap<String, Object> map = Maps.newHashMap(); map.put("id", "1"); Map. put("username", "username"); return this.userFeignClient.get2(map); }Copy the code

Note: This method is not recommended. This is mainly due to poor readability and some problems with null arguments, such as map.put(“username”, null); Causes the service caller (consumer service) to receive a username of “” instead of null.

The original link: http://www.itmuch.com/spring-cloud-sum/feign-multiple-params-2/

Switch to Okhttp3 for improved QPS performance optimization

Add dependencies to introduce OKhttp3

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>${version}</version>
</dependency>Copy the code

Write the configuration

# hystrix: # enabled: true # enable okHTTP disable default httpClient httpClient: enabled: Max-connections: 200 #feign maximum number of connections max-connections-per-route: 50 #fegin maximum number of connections on a single path okhttp: Compression: request: enabled: true min-request-size: 2048 MIME-types: text/xml,application/xml,application/json response: enabled: trueCopy the code

Parameter configuration

/** * set okHTTP to connect pool * ConnectionPool Maintain 5 minutes long connection * / @ Configuration @ ConditionalOnClass (Feign. Class) @ AutoConfigureBefore (FeignAutoConfiguration. Class) Public class OkHttpConfig {// public class OkHttpConfig {// OK @bean public Encoder Encoder() {return new FormEncoder(); } @ Bean public okhttp3. OkHttpClient OkHttpClient () {return new okhttp3. OkHttpClient. Builder () / / sets the connection timeout .connecttimeout (10, timeunit.seconds) // set readTimeout. ReadTimeout (10, timeunit.seconds) // set writeTimeout. WriteTimeout (10, writeTimeout) TimeUnit. SECONDS)/whether/automatic reconnection retryOnConnectionFailure (true). ConnectionPool (new connectionPool (10, 5 l, TimeUnit.MINUTES)) .build(); }}Copy the code

The original link: https://mp.weixin.qq.com/s/PAjXS9d6Sxa04pw1Lw2HXQ

Zhao Xiaopang personal blog