Spring Cloud Feign as a method for HTTP clients to invoke remote HTTP services of recommends

  • 2021-01-11 01:59:10
  • OfStack

In the Spring Cloud Netflix stack, each microservice exposes its own service in the form of an HTTP interface, so the HTTP client must be used when invoking a remote service. We can use JDK native URLConnection, Apache Http Client, Netty asynchronous HTTP Client, Spring RestTemplate. However, Feign is the most convenient and elegant to use.

Feign profile

Feign is a declarative, templated HTTP client. Using Feign in Spring, we can achieve the same coding experience as calling local methods when using HTTP to request a remote service. Developers are completely unaware that this is a remote method, let alone that this is an HTTP request. Such as:


@Autowired
private AdvertGropRemoteService service; //  The remote service 
public AdvertGroupVO foo(Integer groupId) {
 return service.findByGroupId(groupId); //  through HTTP Invoking a remote service 
}

Developers use the service.findByGroupId() The process of sending the HTTP request, decoding the HTTP return result and encapsulating it into an object is completed.

The definition of Feign

In order for Feign to know which address to send a request to when calling a method and which parameters to take with the request, we need to define an interface:


@FeignClient(name = "ea") // [A]
public interface AdvertGroupRemoteService {
 @RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET) // [B]
 AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId) // [C]
 @RequestMapping(value = "/group/{groupId}", method = RequestMethod.PUT)
 void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName)

A: @FeignClient is used to inform the Feign component to proxy this interface (no need to write an interface implementation), which consumers can inject directly through @Autowired.

B: @RequestMapping indicates that the method is required to /group/{groupId} Send the GET request.

C: @PathVariable and SpringMVC corresponding notes have the same meaning.

When the Spring application is started, Feign scans the interface marked with the @FeignClient annotation, generates the proxy, and registers it in the Spring container. Feign creates an RequetTemplate object for each interface method, which encapsulates all the information required by an HTTP request. The request parameter name, request method and other information are determined in this process, and the templating of Feign is reflected here.

In this example, we will use Feign in combination with Eureka and Ribbon ,@FeignClient(name = "ea") Inform Feign to query Eureka for a service named ea when calling this interface method, and get service URL.

Encoder, Decoder and ErrorDecoder of Feign

Feign serializes the method parameter objects in the method signature into request parameters into the HTTP request, which is done by the encoder (Encoder). Similarly, deserialization of HTTP response data into java objects is done by the decoder (Decoder).

By default, Feign adds @RequestParam annotations to URL as strings, and unannotated parameters are converted to json via Jackson into the request body. Note that if method in @RequetMapping specifies the request mode as POST, then all parameters with unlabeled solutions will be ignored, for example:


@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)
void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);

The obj parameter is ignored because the GET request is declared to have no request body.

In Spring Cloud, Encoder* of Feign will only be used to encode unannotated parameters *. If you have custom Encoder, then your Encoder will only be called when you encode the obj parameter. For Decoder, the default is to delegate the decoding to the MappingJackson2HttpMessageConverter class in SpringMVC. ErrorDecoder is called only if the status code is not between 200 and 300. The function of ErrorDecoder is to return an exception based on HTTP response information, which can be caught at the point where the Feign interface is called. We are currently using ErrorDecoder to enable the Feign interface to throw a business exception for the caller to handle.

The Feign HTTP Client

Feign by default uses JDK native URLConnection to send HTTP requests. There is no connection pooling, but one long connection is maintained for each address, which is persistence connection using HTTP. We can replace Feign's original http client with Apache's HTTP Client to gain performance-related control over connection pooling, timeout, and so on. Spring Cloud supports this replacement from Brixtion.SR5, starting with the declaration of Apache HTTP Client and Client in the project feign-httpclient Rely on:


<!--  use Apache HttpClient replace Feign native httpclient -->
 <dependency>
 <groupId>org.apache.httpcomponents</groupId>
 <artifactId>httpclient</artifactId>
 </dependency>
 <dependency>
 <groupId>com.netflix.feign</groupId>
 <artifactId>feign-httpclient</artifactId>
 <version>${feign-httpclient}</version>
 </dependency>

Then add in application.properties:


feign.httpclient.enabled=true

conclusion

With Feign, we can make HTTP remote calls completely transparent to developers, giving us a coding experience comparable to calling native methods. This point is similar to the way Ali's Dubbo exposes remote services, the difference is that Dubbo is based on a private binary protocol, while Feign is essentially an HTTP client. If you are building a microservice with Spring Cloud Netflix, then Feign is definitely the best choice.


Related articles: