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
Feign
annotations andJAX-RS
annotations; - Support HTTP encoder and decoder;
- Support
Hystrix
and its Fallback; - Support
Ribbon
load 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 | "PRODUCT-SERVICE") (value = |
Note: if your service compiles a jar package separately, you need to specify the value of
basePackages
when using the@EnableFeignClients
annotation. Otherwise, there will be an error reportingProductService
bean cannot be found when autowiring.
1 | "com.feigndemo.**") (basePackages = |
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 | "/products", method = RequestMethod.GET) (value = |
We are using Spring MVC annotations. The annotations we commonly use in Spring MVC are:
@RequestParam
binds a single request parameter value;@PathVariable
binds the URI template variable value;@RequestHeader
binds the request header data;@RequestBody
binds the requested content area data and can perform automatic type conversion, etc.
Example of using @RequestParam
, @PathVariable
, and @RequestHeader
:
1 | "/products/detail", method = RequestMethod.GET) (value = |
Of course, we can also use multiple parameter binding, as follows:
1 | "/products/{itemCode}", method = RequestMethod.POST) (value = |
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 | "/users/register", method = RequestMethod.POST) (value = |
When using it, you need to pay attention that
User
object must have a default constructor, otherwiseFeign
will not be able to convert to theUser
object according to the JSON string, thereby throwing an exception, causing the call to fail.
Check out the source code here: Feign demo