Feign declarative remote call
1. Introduction
Feign is a declarative HTTP client. Its purpose is to make remote calls easier. Feign provides the template of HTTP request. By writing a simple interface and inserting annotations, you can define the parameters, format, address and other information of HTTP request.
Feign integrates Ribbon (load balancing) and hystrix (service fusing), so that we no longer need to explicitly use these two components.
Spring cloudfeign extends the support for spring MVC annotation on the basis of NetflixFeign. Under its implementation, we only need to create an interface and configure it in the way of annotation to complete the interface binding to the service provider. It simplifies the development of spring cloudribbon's self encapsulated service call client
2. How to use it?
Steps:
- Guide Package
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
Create an interface and add @ FeignClient(name = "service name to be called") to the interface
-
Add EnableClients(basePackages = "package name of feign interface") to the startup class
Summary:
It is recommended to use the modular method. When writing a service, the service is divided into three modules:- The clien module is used to place the feign interface so that other services can rely on it directly
- The common module is used to store some entity classes or tools common to each microservice
- server module service core module
For example:
3. Composition
The attributes listed above can be referenced Feign official website configuration Configure
principle
4.Feign log
Feign does not output logs by default. How to configure log output for feign?
Refer to the official website: Configure feign logs on the official website
Feign's log level:
level | print contents |
---|---|
None (default) | No logs are logged |
BASIC | Only record the request method, URL, response status code and execution time (most commonly used) |
HEADERS | Record the header of request and response based on the BASIC level |
FULL | Record the header, body and metadata of the request and response |
Problem 1: fine grained configuration
Use Java code to make the specific Feign interface Full log level
Solution 1:
// Customize an interface: @FeignClient(name = "user-center",configuration = UserCenterFeignConfiguration.class) public interface UserCenterFeignClient { /** * http://user-center/users/{id} * @param id * @return */ @GetMapping("/users/{id}") UserDTO findById(@PathVariable Integer id); } /** Write another configuration class: The Configuration class is not annotated with @ Configuration, otherwise it must be moved outside the package scanned by @ Component. If it is added and not moved outside the package scanned above, the log level of all Feign defined by us will be FULL. This problem is a typical parent-child context problem */ public class UserCenterFeignConfiguration { @Bean public Logger.Level level() { return Logger.Level.FULL; } } // Finally, we need to add configuration to the configuration file to make complaints about it. logging: level: /**The purpose of adding the full path of feign interface here is that if you want to print feign logs, you must establish the log level of feign interface as debug*/ com: ray: content_center: feignclient: UserCenterFeignClient: debug
Solution 2: attribute configuration method
@FeignClient(name = "user-center") public interface UserCenterFeignClient { /** * http://user-center/users/{id} * @param id * @return */ @GetMapping("/users/{id}") UserDTO findById(@PathVariable Integer id); } feign: client: config: #The name of the micro service you want to call user-center: loggerLevel: full
Question 2: global configuration
Implement all Feign interfaces in Java code to specify the log level
- Method 1: the parent-child context problem of our fine-grained configuration above (not recommended)
- Method 2: in @ EnableFeignClients(defaultConfiguration=xxx.class)
Configure attribute modepublic class xxx { @Bean public Logger.Level level() { return Logger.Level.FULL; } }
feign: client: config: #Global configuration default: loggerLevel: full
5. Configuration best practice summary
6. Multi parameter request construction
Tips: Version: Spring Cloud Greenwich SR1, which theoretically supports higher versions
GET request multi parameter URL
Suppose that the URL to be requested contains multiple parameters, such as http://localhost:8080/get?id=1&userName= "ray", how to use Feign construction?
Through the official website, we know that Feign has added annotation support for Spring MVC: then try a wave
public class User{ String userName; Long id; } @FeignClient("user-service") public interface UserFeignClient { @RequestMapping(value = "/get", method = RequestMethod.GET) public User get(User user); }
However, this method is not correct. The console outputs the following exceptions:
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"}
It can be seen from the exception that Feign will still send the request using the POST method even though we specify the GET method
The correct wording is as follows:
- Mode 1: Recommended on the official website
@FeignClient("user-service") public interface UserFeignClient { @GetMapping("/get") public User get(@SpringQueryMap User user); }
- Mode 2:
@FeignClient(name = "user-service") public interface UserFeignClient { @RequestMapping(value = "/get", method = RequestMethod.GET) public User get(@RequestParam("id") Long id, @RequestParam("username") String userName); }
The POST request contains multiple parameters
Suppose the Controller of the service provider is as follows:
@RestController public class UserController { @PostMapping("/post") public User post(@RequestBody User user) {} }
How do we use Feign to request? As follows:
@FeignClient(name = "user-service") public interface UserFeignClient { @PostMapping("/post") public User post(@RequestBody User user); }
7.Feign is used without Ribbon
How does Feign call a service that is not registered with the registry?
For example, I want to call Baidu: www.baidu.com com
//The name here must be written, or an error will be reported @FeignClient(name = "baidu", url = "http://www.baidu.com") public interface TestBaiduFeignClient { @GetMapping("") String index(); }
Other scenarios:
For example, if you want to call the HTTP interface of an external system, you can play like this.
Two examples:
- You want to call Alipay's HTTP API;
- Your Spring Cloud microservice wants to call the interface of the legacy project (the legacy project has not had time to reconstruct the Spring Cloud)
In short, Feign itself is an HTTP client. You can use Feign to send HTTP requests you want to send. Where do you want to request
8.RestTemplate VS Feign
angle | RestTemplate | Feign |
---|---|---|
Readability, maintainability | commonly | very good |
Development experience | Poor | very good |
performance | very good | Medium (about 50% of RestTemplate) |
flexibility | very good | Medium (built-in function can meet most requirements) |
How to choose?
Principle: use Feign as much as possible, avoid using RestTemplate, and choose reasonably
9. Feign's performance optimization
- Connection pool (increased by about 15%)
1.use apache httpclient Optimized Import dependency first: <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency> feign: httpclient: # Let feign use apache httpclient to make requests; Instead of the default urlconnection enabled: true # Maximum connections for feign max-connections: 200 # feign maximum number of connections for a single path max-connections-per-route: 50 2.use okhttpclient optimization Similarly, the package is introduced to write configuration
- Log level (set to BASIC)