1 Introduction
Nacos
in Spring Cloud was introduced earlier. Compared with its predecessors, it is not only powerful, but also very simple to deploy.
Today, we will introduce a service call component: OpenFeign
, which is also a Ribbon
that surpasses the ancestors (061d5501225f81, Feign
).
The article catalog is as follows:
2. What is Feign?
Feign is also a ruthless character, Feign aims to make the Java Http client easier.
Feign integrates Ribbon and RestTemplate to implement load-balanced execution of Http calls, but it encapsulates the original method (Ribbon+RestTemplate). Developers do not need to manually use RestTemplate to adjust services, but define an interface in this interface. An annotation can be marked to complete the service call, which is more in line with the purpose of interface-oriented programming and simplifies development.
Unfortunately, Feign has stopped iterating. Of course, many companies are using it now.
Readers who want to learn Feign can go to the spring Cloud official website to learn. Chen will not introduce it in detail here, which is not the focus of today.
3. What is openFeign?
I introduced Feign that stops iteration. To put it simply: OpenFeign is springcloud supporting SpringMVC annotations on the basis of @RequestMapping
, such as 061d5501226037 and so on. OpenFeign's @FeignClient
can parse @RequestMapping
annotation, and generate implementation classes through dynamic proxy, implement load balancing in the class and call other services.
Official website address: https://docs.spring.io/spring-cloud-openfeign/docs/2.2.10.BUILD-SNAPSHOT/reference/html
4. What is the difference between Feign and openFeign?
Feign | openFiegn |
---|---|
Feign is a lightweight RESTful HTTP service client in the SpringCloud component. Feign has built-in Ribbon, which is used for client load balancing to call the service of the service registry. The way to use Feign is: use Feign's annotations to define the interface, call this interface, you can call the service of the service registry | OpenFeign is that SpringCloud supports SpringMVC annotations, such as @RequestMapping, on the basis of Feign. OpenFeign's @FeignClient can parse the interface under SpringMVC's @RequestMapping annotation, and generate implementation classes through dynamic proxy, implement load balancing in the class and call other services. |
5. Environmental preparation
The Spring Cloud version, JDK environment, and project environment of this article are the same as those of the previous Nacos: 161d550122613a Fifty-five pictures tell you how strong is Nacos, the soul .
The registration center no longer uses Eureka
, and directly uses Nacos
as the registration and configuration center. If you don’t, you can view the Nacos article.
The project structure built in this article is as follows:
The registration center uses Nacos to create a microservice, which is the service provider Produce , and the service consumer Consumer .
6. Create a service provider
openFeign-provider9005
, there must be a service provider. Create 061d5501226227 and register it in Nacos. The configuration is as follows:
server:
port: 9005
spring:
application:
## 指定服务名称,在nacos中的名字
name: openFeign-provider
cloud:
nacos:
discovery:
# nacos的服务地址,nacos-server中IP地址:端口号
server-addr: 127.0.0.1:8848
management:
endpoints:
web:
exposure:
## yml文件中存在特殊字符,必须用单引号包含,否则启动报错
include: '*'
Note : here spring.application.name
specified name will be used in openFeign the interface call.
The source code of the project will be uploaded. Regarding how to register into Nacos, there will be any dependent source code added. Combined with Chen's previous Nacos article, this is not difficult!
7. Create service consumers
Create a new module openFeign-consumer9006
as a consumer service, the steps are as follows.
1. Add dependencies
In addition to the dependency of the registry of Nacos, the dependency of openFeign must be added, as follows:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. Add the annotation @EnableFeignClients to enable the openFeign function
The old routine is gone, add an annotation @EnableFeignClients
Spring boot main startup class to enable the openFeign function, as follows:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OpenFeignConsumer9006Application
{
public static void main(String[] args) {
SpringApplication.run(OpenFeignConsumer9006Application.class, args);
}
}
3. Create a new openFeign interface
Create a new openFeign interface, use @FeignClient
annotation mark, as follows:
@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
}
Note : Thevalue
attribute in@FeignClient
service name the service provider in the nacos registry.
4. Create a new Controller to debug
Create a new controller to debug the interface, and directly call the interface of openFeign, as follows:
@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {
}
Ok, so far, an openFeign microservice has been built, and no specific functions have been implemented. The following is a little bit of implementation.
8. How to transfer parameters in openFeign?
There are many ways to pass parameters in an interface during development, but there are certain rules for passing parameters in openFeign, which are described in detail below.
1. Pass JSON data
This is also a commonly used parameter passing rule in interface development, which is identified @RequestBody
The JSON parameter passing method in the provider interface is as follows:
@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
@PostMapping("/order2")
public Order createOrder2(@RequestBody Order order){
return order;
}
}
The parameter code in the openFeign interface of the consumer is as follows:
@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
/**
* 参数默认是@RequestBody标注的,这里的@RequestBody可以不填
* 方法名称任意
*/
@PostMapping("/openfeign/provider/order2")
Order createOrder2(@RequestBody Order order);
}
Note: openFeign
default parameter passing JSON way to pass parameters ( @RequestBody
), thus defining the interface when you can not @RequestBody
notes marked, but in order to regulate, generally fill.
2. POJO form parameter transfer
This way of passing parameters is also commonly used, and the parameters are received using POJO objects.
The provider service provider code is as follows:
@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
@PostMapping("/order1")
public Order createOrder1(Order order){
return order;
}
}
The consumer consumer openFeign code is as follows:
@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
/**
* 参数默认是@RequestBody标注的,如果通过POJO表单传参的,使用@SpringQueryMap标注
*/
@PostMapping("/openfeign/provider/order1")
Order createOrder1(@SpringQueryMap Order order);
}
Many people on the Internet are wondering how to transfer parameters in POJO form. The official document clearly gives a solution, as follows:
openFeign provides an annotation @SpringQueryMap
perfectly solve the POJO form parameter transfer.
3. Carrying parameters in the URL
This method is for the GET request in the restful method, and it is also a common request method.
The provider service provider code is as follows:
@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
@GetMapping("/test/{id}")
public String test(@PathVariable("id")Integer id){
return "accept one msg id="+id;
}
The consumer consumer openFeign interface is as follows:
@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
@GetMapping("/openfeign/provider/test/{id}")
String get(@PathVariable("id")Integer id);
}
Use the annotation @PathVariable
receive the placeholder in the url, which is easy to understand.
4. Common form parameters
This method of parameter transfer is not recommended, but it is also used by many developers.
The provider service provider code is as follows:
@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
@PostMapping("/test2")
public String test2(String id,String name){
return MessageFormat.format("accept on msg id={0},name={1}",id,name);
}
}
The consumer consumer openFeign interface passes parameters as follows:
@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
/**
* 必须要@RequestParam注解标注,且value属性必须填上参数名
* 方法参数名可以任意,但是@RequestParam注解中的value属性必须和provider中的参数名相同
*/
@PostMapping("/openfeign/provider/test2")
String test(@RequestParam("id") String arg1,@RequestParam("name") String arg2);
}
5. Summary
There are many ways to transfer parameters, such as file transfer... Chen just listed four common ways to transfer parameters.
9. How to deal with timeout?
To understand the timeout handling, let’s look at an example first: I sleep the provider service interface for 3 seconds, the interface is as follows:
@PostMapping("/test2")
public String test2(String id,String name) throws InterruptedException {
Thread.sleep(3000);
return MessageFormat.format("accept on msg id={0},name={1}",id,name);
}
At this point, we call the consumer's openFeign interface to return the result as shown below:
It is obvious that the program is abnormal, and the interface call timeout is returned. what? why? ...........
openFeign actually has a default timeout period. The default is connection timeout time 10 seconds, read timeout time
60 seconds, the source code is in
feign.Request.Options#Options()
, as shown in the figure below:
So the question is here: Why do I only set the sleep for 3 seconds and then report the timeout?
In fact, openFeign integrates Ribbon. Ribbon’s default timeout connection time and read timeout time are both 1 second. The source code is in the org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute()
method, as shown below:
source code roughly means : If openFeign does not set the corresponding timeout time, then the Ribbon default timeout time will be used.
After understanding the principle of timeout setting, it is also very clear to produce two solutions, as follows:
- Set the timeout period of openFeign
- Set Ribbon timeout
1. Set the ribbon timeout time (not recommended)
The setting is very simple, add the following settings in the configuration file:
ribbon:
# 值的是建立链接所用的时间,适用于网络状况正常的情况下, 两端链接所用的时间
ReadTimeout: 5000
# 指的是建立链接后从服务器读取可用资源所用的时间
ConectTimeout: 5000
2. Set the timeout period of openFeign (recommended)
OpenFeign is very simple to set the timeout time, only need to be configured in the configuration file, as follows:
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
The default setting is the global timeout time, which is effective for all openFeign interface services
However, the normal business logic may involve multiple openFeign interface calls, as shown in the following figure:
The pseudo code in the figure above is as follows:
public T invoke(){
//1. 调用serviceA
serviceA();
//2. 调用serviceA
serviceB();
//3. 调用serviceA
serviceC();
}
Can the global timeout configured above be passed? Obviously serviceA
and serviceB
can be called successfully, but serviceC
cannot be successfully executed, and it must report a timeout.
At this point, we can configure a separate timeout period for the service serviceC
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
## 为serviceC这个服务单独配置超时时间
serviceC:
connectTimeout: 30000
readTimeout: 30000
Note : The timeout period of a single configuration will overwrite the global configuration.
10. How to enable log enhancement?
Although openFeign provides log enhancements, it does not display any logs by default, but developers can configure the log level during the debugging phase.
The log levels of openFeign are as follows:
- NONE : By default, no logs are displayed;
- BASIC : Only record the request method, URL, response status code and execution time;
- HEADERS : In addition to the information defined in BASIC, there are request and response header information;
- FULL : In addition to the information defined in HEADERS, there are also the body and metadata of the request and response.
The configuration is also very simple, the steps are as follows:
1. Configure the log level in the configuration class
You need to customize a configuration class and set the log level in it, as follows:
Note : The logger here is in the feign package.
2. Set the interface log level in the yaml file
You only need to adjust the interface log level of the specified package or openFeign in the configuration file, as follows:
logging:
level:
cn.myjszl.service: debug
Here cn.myjszl.service
is the package name where the openFeign interface is located. Of course, you can also configure a specific openFeign interface.
3. Demonstration effect
In the above steps, the log is set to FULL
, and the request is issued at this time, and the log effect is as shown in the figure below:
The contents of the request header and request body are printed out in the log in detail.
11. How to replace the default httpclient?
Feign uses the JDK native URLConnection send HTTP requests by default. There is no connection pool, but a long connection is maintained for each address, that is, the persistence connection of HTTP is used.
In a production environment, the default http client is usually not used, and there are usually two choices as follows:
- Use ApacheHttpClient
- Use OkHttp
As for which is better, each has its own advantages and disadvantages. I prefer ApacheHttpClient. After all, it is an old brand and stability is not a problem.
So how to replace it? In fact, it is very simple, the following demonstration uses ApacheHttpClient to replace.
1. Add ApacheHttpClient dependency
Add the following dependencies to the pom file of the openFeign interface service:
<!-- 使用Apache HttpClient替换Feign原生httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
Why add the above dependency? It is not difficult to see from the source code, please look org.springframework.cloud.openfeign.FeignAutoConfiguration.HttpClientFeignConfiguration
the class 061d5501226fda, the code is as follows:
Generating condition of the red frame, wherein the @ConditionalOnClass(ApacheHttpClient.class)
, must be ApacheHttpClient
class to take effect, and feign.httpclient.enabled
this configuration to be set to true
.
2. Open in the configuration file
To enable configuration in the configuration file, the code is as follows:
feign:
client:
httpclient:
# 开启 Http Client
enabled: true
3. How to verify that the replacement has been successful?
In fact, it is very simple. You can clearly see which client is called feign.SynchronousMethodHandler#executeAndDecode()
In the figure above, you can see that the final call is ApacheHttpClient
.
4. Summary
The above steps only demonstrate one alternative scheme, and the remaining one will not be demonstrated anymore, and the principle is the same.
12. How to optimize communication?
Before talking about how to optimize, take a look at the GZIP compression algorithm, the concept is as follows:
gzip is a data format that uses the deflate algorithm to compress data; gzip is a popular data compression algorithm, which is widely used, especially on the Linux platform.
When GZIP compresses to a plain text data, the effect is very obvious, and the data size can be reduced by more than 70%.
After the network data is compressed, the number of bytes transmitted on the network is actually reduced. The most obvious benefit is that it can speed up the loading of web pages. The benefits of faster web page loading speed are self-evident. In addition to saving traffic and improving users' browsing experience, another potential benefit is that GZIP has a better relationship with search engine crawling tools. For example, Google can retrieve web pages faster than ordinary manual crawling by directly reading GZIP files.
The principle of GZIP compression transmission is as follows:
The steps to disassemble according to the above figure are as follows:
- The client requests the server with the
Accept-Encoding:gzip,deflate
, which indicates to the server that the client supports the compression format (gzip or deflate). If the message header is not sent, the server will not compress it. - After the server receives the request, if it finds that the request header contains the
Accept-Encoding
field and supports this type of compression, it compresses the response message and returns it to the client, and carries theContent-Encoding:gzip
message header, indicating that the response message is based on this format Compressed. - After the client receives the response, it first determines whether there is a Content-Encoding message header, and if so, decompresses the message according to the format. Otherwise, it is processed as a normal message.
openFeign supports request/response enable GZIP compression, the overall process is as follows:
In the above figure, there are only two pieces involved in GZIP transmission, namely Application client -> Application Service and Application Service->Application client .
Note : GZIP supported by openFeign is only the request and response on the openFeign interface, that is, the interface for openFeign consumers to call the service provider.
The steps to open GZIP on openFeign are also very simple, you only need to open the following configuration in the configuration file:
feign:
## 开启压缩
compression:
request:
enabled: true
## 开启压缩的阈值,单位字节,默认2048,即是2k,这里为了演示效果设置成10字节
min-request-size: 10
mime-types: text/xml,application/xml,application/json
response:
enabled: true
After the above configuration is completed, send a request, you can clearly see that GZIP compression has been carried in the request header, as shown in the following figure:
13. How to fuse downgrade?
The common fuse downgrade frameworks are Hystrix
and Sentinel
. The default support for Hystrix
is 061d550122734b. This is reflected in the official documentation. After all, it is a compatriot, haha...........
However, Ali's Sentinel completely kills Hystrix in terms of features, simplicity and openFeign+Sentinel to integrate and achieve service degradation.
Description : This article does not focus on Sentinel, Chen intends to introduce the power of Sentinel in detail in the next article.
1. Add Sentinel dependency
openFeign-consumer9006
(due to the use of the aggregation module, the version number is not specified), as follows:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2. Turn on sentinel fuse downgrade in the configuration file
If you want openFeign to use sentinel's downgrade function, you also need to enable it in the configuration file and add the following configuration:
feign:
sentinel:
enabled: true
3. Add a downgrade callback class
This class must implement the same class as the openFeign interface, as shown below:
OpenFeignFallbackService
is a class for downgrade callback. Once the OpenFeignService
is abnormal, the corresponding method in this class will be called for downgrade processing.
4. Add fallback attribute
In @FeignClient
added in fallback
attribute, attribute value is degraded callback class as follows:
@FeignClient(value = "openFeign-provider",fallback = OpenFeignFallbackService.class)
public interface OpenFeignService {}
5. Demo
After the above 4 steps, the fuse downgrade of openFeign has been set up, and the effect is demonstrated at this time.
http://localhost:9006/openfeign/order3
through postman, and the normal logic returns as shown below:
Now create an exception manually and throw an exception in the interface provided by the service, as shown below:
At this time, call http://localhost:9006/openfeign/order3
, and return to the following picture:
Oh, you can clearly see that the service has been successfully degraded and called, oh, the function is complete.
Note : The results returned in the actual development should be uniformly customized according to the architecture. Chen is here only for the convenience of demonstration, don't learn from it, haha. . .
14. Summary
This article is mainly for beginners. The in-depth source code and circuit breaker downgrading will be introduced in detail later. If there is any unclear expression in the article, please correct me if there is any mistake!
This is the second article of Chen's Spring Cloud advanced column. I think the article is good, welcome to like, bookmark, and forward.
The above source code has been uploaded to GitHub, and the required public number [Code Ape Technology Column] is obtained by replying to the keyword 9528
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。