In the previous blog, we can find that when we call the API through RestTemplate, the parameters must be spliced in the request URL. If there are only a few parameters, we may still be able to tolerate it. Once there are multiple parameters, then splicing the request string would be inefficient and seem silly. So is there a better solution? The answer is yes, Netflix has provided us with a framework: Feign.
Feign is a declarative Web Service client, and its purpose is to make Web Service calls easier. Feign provides a template for HTTP requests. By writing a simple interface and annotations, you can define the parameters, format, and address of the HTTP request. Feign will proxy HTTP requests, and we only need to call it like a method to complete the service request.
Feign integrates Ribbon and Hystrix (I will talk about Hystrix later), so that we no longer need to use these two components explicitly. In addition, Spring Cloud also provides Spring MVC annotation support for Feign, which also allows us to use the same HttpMessageConverter in the Web.
In summary, Feign has the following characteristics:
- Annotation support, including
Feignannotations andJAX-RSannotations; - Support HTTP encoder and decoder;
- Support
Hystrixand its Fallback; - Support
Ribbonload balancing; - Supports compression of HTTP requests and responses.
Example Project
In this example we will build an e-mall project. We have a Product-Service provides product services. It is an Eureka Client, and is a service provider. Product-Service-Consumer is also an Eureka Client. As a service consumer, it uses Feign. The Service-Discovery remains unchanged (we can directly reuse the code in previous article).
Product-Service
1. pom.xml
Product-Service is a standard Eureka Client, so pom.xml is the same as the previous Service-Hello
1 | <dependencies> |
2. Main class
1 |
|
This is same as previous blogs
3. Product entity
1 | public class Product { |
4. Product service
1 |
|
This service provides the following two interfaces:
- list: get product list;
- detail: get detailed data of the specified product.
5. application.properties
1 | eureka.client.service-url.defaultZone=http://localhost:8761/eureka |
6. Launch Testing
Start Service-discovery and Product-Service, we can see that PRODUCT-SERVICE has registered in the Eureka server.
Product-Service-Consumer
1. pom.xml
1 | <dependencies> |
2. Main class
1 |
|
We added the @EnableFeignClients annotation to the startup class to enable Feign related functions.
3. Service call class
Spring Cloud creates a proxy class that can be called directly by the application according to this interface. In order to complete the proxy, we need to add some annotations, where @FeignClient is the PRODUCT-SERVICE defined by the Product-Service. @RequestMapping is an annotation of SpringMVC, which corresponds to two API interfaces provided in the Product-Service.
1 | (value = "PRODUCT-SERVICE") |
Note: if your service compiles a jar package separately, you need to specify the value of
basePackageswhen using the@EnableFeignClientsannotation. Otherwise, there will be an error reportingProductServicebean cannot be found when autowiring.
1 | (basePackages = "com.feigndemo.**") |
4. Controller
The Controller is a standard SpingMVC Controller, which is used to provide users with specific services.
1 |
|
5. application.properties
1 | eureka.client.service-url.defaultZone=http://localhost:8761/eureka |
6. Launch Testing
Start Product-Service-Consumer, and visit: http://localhost:9090/products
And visiting http://localhost:9090/products/item-3
Parameter Binding
Feign supports a variety of annotations. When using Feign, we can use Feign‘s own annotations or JAX-RS annotations as needed. Spring Cloud has enhanced Feign so that Feign supports Spring MVC annotations. As above code:
1 | (value = "/products", method = RequestMethod.GET) |
We are using Spring MVC annotations. The annotations we commonly use in Spring MVC are:
@RequestParambinds a single request parameter value;@PathVariablebinds the URI template variable value;@RequestHeaderbinds the request header data;@RequestBodybinds the requested content area data and can perform automatic type conversion, etc.
Example of using @RequestParam, @PathVariable, and @RequestHeader:
1 | (value = "/products/detail", method = RequestMethod.GET) |
Of course, we can also use multiple parameter binding, as follows:
1 | (value = "/products/{itemCode}", method = RequestMethod.POST) |
Pass object as parameter
When we define an interface, we often include an object in the parameters. For example, our service interface is as follows:
1 | User register(User user); |
So how to pass complex user object? Just use the @RequestBody as follows:
1 | (value = "/users/register", method = RequestMethod.POST) |
When using it, you need to pay attention that
Userobject must have a default constructor, otherwiseFeignwill not be able to convert to theUserobject according to the JSON string, thereby throwing an exception, causing the call to fail.
Check out the source code here: Feign demo