1.OpenFeign 是什么:
1.1.几个网址:
1.2.OpenFeign使用:
- 1.OpenFeign
是一个声明式 Web服务客户端
,使用 OpenFeign 让编写 Web 服务客户端更简单 - 2.它的使用方法是:
定义一个Rest服务接口,然后在上面添加注解@FeignClient即可
OpenFeign基本就是当前微服务之间调用的事实标准
,OpenFeign它也包含了负载均衡的功能
2.OpenFeign 能干嘛:
2.1.OpenFeign 功能:
2.2.为何选择OpenFeign:
a.非OpenFeign的实现服务调用:
- 1.前面在使用
SpringCloud LoadBalancer+RestTemplate
时,利用RestTemplate对http请求的封装处理形成了一套模版化的调用方法。
- 2.但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,如果是使用RestTemplate来调用的话,每个系统都需要new一份RestTemplate,如果系统多的话,就会new出来各种各样的RestTemplate,不好管理
- 3.在开发的时候,我们也倡导面向接口编程,应该是被调用的系统有一套规则,对外暴漏一个接口,只要是想调用它,就先找到这个接口,基于这个接口,进行调用的实现就可以了,基于以上几点,就出现了OpenFeign
a.OpenFeign实现服务调用:
- 1.在OpenFeign的实现下,我们只需创建一个接口并使用注解的方式来配置它(在一个微服务接口上面标注一个
@FeignClient
注解即可),即可完成对服务提供方的接口绑定,统一对外暴露可以被调用的接口方法,大大简化和降低了调用客户端的开发量,也即由服务提供者给出调用接口清单,消费者直接通过OpenFeign调用即可,O(∩_∩)O。 - 2.
OpenFeign同时还集成SpringCloud LoadBalancer,可以在使用OpenFeign时提供Http客户端的负载均衡,也可以集成阿里巴巴Sentinel来提供熔断、降级等功能
。而与SpringCloud LoadBalancer不同的是,通过OpenFeign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
3.OpenFeign实现服务调用的通用步骤:
3.1.接口 + 注解
- 1.微服务Api接口(对外暴露我有哪些接口可以被调用) + @FeignClient注解标签
3.2.架构说明图:
服务消费者80 → 调用含有@FeignClient注解的Api服务接口 → 服务提供者(8001/8002)
3.3.架构实现的流程步骤:
a.新建模块moudle:
- 1.本模块是订单服务模块,模块的名称是
cloud-consumer-feign-order80
,作为消费端 - 2.Feign是在消费端使用的
b.改pom → 引入OpenFeign 依赖:
- 1.引入依赖:
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 2.整个pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.atguigu.cloud</groupId>
<artifactId>mscloudV5</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>cloud-consumer-feign-order80</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--SpringCloud consul discovery-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- 引入自己定义的api通用包 -->
<dependency>
<groupId>com.atguigu.cloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web + actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-all-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!--fastjson2-->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
c.写YML → 将此模块注册到consul:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
d.主启动
- 1.在主启动类上填写
@EnableFeignClients
.表示开启OpenFeign功能并激活
e.业务类:
e1.按照架构说明图进行编码准备:
- 1.
订单模块要去调用支付模块
,订单和支付两个微服务,需要通过Api接口解耦,一般不要在订单模块写非订单相关的业务,自己的业务自己做+其它模块走FeignApi接口调用; - 2.在这里
订单服务80通过调用公共的接口去调用支付8001服务
,当然其他模块也可能通过公共模块来调用8001服务
e2.修改cloud-api-commons
通用模块:
- 1.引入openfeign依赖:
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 2.新建服务接口PayFeignApi,头上配置
@FeignClient
注解,然后参考微服务8001的controller层,新建PayFeignApi接口:
e3.修改消费端80服务的controller层:
package com.atguigu.cloud.controller;
import com.atguigu.cloud.apis.PayFeignApi;
import com.atguigu.cloud.entities.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
public class OrderController{
@Resource
private PayFeignApi payFeignApi;
@PostMapping("/feign/pay/add")
public ResultData addOrder(@RequestBody PayDTO payDTO){
System.out.println("第一步:模拟本地addOrder新增订单成功(省略sql操作),第二步:再开启addPay支付微服务远程调用");
ResultData resultData = payFeignApi.addPay(payDTO);
return resultData;
}
@GetMapping("/feign/pay/get/{id}")
public ResultData getPayInfo(@PathVariable("id") Integer id){
System.out.println("-------支付微服务远程调用,按照id查询订单支付流水信息");
ResultData resultData = payFeignApi.getPayInfo(id);
return resultData;
}
/**
* openfeign天然支持负载均衡演示
*
* @return
*/
@GetMapping(value = "/feign/pay/mylb")
public String mylb(){
return payFeignApi.mylb();
}
}
3.4.测试:
- 1.启动consul服务器
- 2.启动8001服务和启动8002服务;启动cloud-consumer-feign-order80服务
- 3.PostMan测试、
- 4.查询操作:
- 5.负载均衡测试:
3.5.总结:
4.OpenFeign的高级特性:
4.1.OpenFeign超时控制
a.本次OpenFeign的版本要注意,最新版和网络上看到的配置不一样
- 1.在Spring Cloud微服务架构中,大部分公司都是利用OpenFeign进行服务间的调用,而比较简单的业务使用默认配置是不会有多大问题的,但是如果是业务比较复杂,服务要进行比较繁杂的业务计算,那后台很有可能会出现Read Timeout这个异常,因此定制化配置超时时间就有必要了
b.超时设置,故意设置超时演示出错情况:
b1.服务提供方8001故意写暂停62秒钟程序:
为什么写62秒?为什么写62秒?为什么写62秒?
OpenFeign默认等待60秒钟,超时后报错
b2.服务调用方80写好捕捉超时异常:
@GetMapping("/feign/pay/get/{id}")
public ResultData getPayInfo(@PathVariable("id") Integer id)
{
System.out.println("-------支付微服务远程调用,按照id查询订单支付流水信息");
ResultData resultData = null;
try
{
System.out.println("调用开始-----:"+DateUtil.now());
resultData = payFeignApi.getPayInfo(id);
} catch (Exception e) {
e.printStackTrace();
System.out.println("调用结束-----:"+DateUtil.now());
ResultData.fail(ReturnCodeEnum.RC500.getCode(),e.getMessage());
}
return resultData;
}
-
3.测试
-
4.结论:OpenFeign默认等待60秒钟,超时后报错
c.官网解释 + 配置处理
c1.两个参数:
- 1.默认OpenFeign客户端等待60秒钟,但是服务端处理超过规定时间会导致Feign客户端返回报错。为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制,默认60秒太长或者业务时间太短都不好
- 2.yml文件中开启配置:
- connectTimeout:连接超时时间
- readTimeout:请求处理超时时间
c2.超时配置官网要求:
d.配置超时时间:
通过修改
cloud-consumer-feign-order-80
的yml文件,里面需要开启OpenFeign客户端超时控制
d1.官网出处:
d2.全局配置
- 1.关键内容
spring:
cloud:
openfeign:
client:
config:
default:
#连接超时时间
connectTimeout: 3000
#读取超时时间
readTimeout: 3000
- 2.全部配置:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
#连接超时时间
connectTimeout: 3000
#读取超时时间
readTimeout: 3000
- 3.进行3秒测试:
d3.指定配置:
- 1.指定单个服务配置超时时间举例
spring:
cloud:
openfeign:
client:
config:
# default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
#连接超时时间
connectTimeout: 4000
#读取超时时间
readTimeout: 4000
# 为serviceC这个服务单独配置超时时间,单个配置的超时时间将会覆盖全局配置
serviceC:
#连接超时时间
connectTimeout: 2000
#读取超时时间
readTimeout: 2000
- 2.本模块中配置超时时间的关键内容
spring:
cloud:
openfeign:
client:
config:
cloud-payment-service:
#连接超时时间
connectTimeout: 5000
#读取超时时间
readTimeout: 5000
- 3.全部的yml文件内容:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
#default:
#connectTimeout: 4000 #连接超时时间
#readTimeout: 4000 #读取超时时间
cloud-payment-service:
connectTimeout: 8000 #连接超时时间
readTimeout: 8000 #读取超时时间
- 4.进行5秒测试:
4.2.OpenFeign重试机制:
a.步骤:
a1.重试机制的默认值:
- 1.重试机制默认是关闭的,给了默认值
a2.测试重试机制的默认值:
a3.开启Retryer功能:
- 1.修改配置文件YML的配置:
- 2.新增配置类:
package com.atguigu.cloud.config;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig
{
@Bean
public Retryer myRetryer()
{
//return Retryer.NEVER_RETRY; //Feign默认配置是不走重试策略的
//最大请求次数为3(1+2),初始间隔时间为100ms,100ms之后启动重试机制,重试间最大间隔时间为1s
return new Retryer.Default(100,1,3);
}
}
4.结果:总体调用3次:
b.说明:
- 1.报错只是打印了一个最终的结果,而不是调用一次打印一次日志,感觉效果不明显,控制台没有看到3次重试过程,这是feign的日志打印问题
4.3.OpenFeig默认HttpClient修改:
a.是什么:
- 1.OpenFeign中http client:如果不做特殊配置,
OpenFeign默认使用JDK自带的HttpURLConnection发送HTTP请求
,由于默认HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,性能上不是最牛B的,所以需要对其进行替换
b.替换之前,还是按照超时报错的案例:
c.Appache HttpClient 5替换OpenFeign默认的HttpURLConnection:
c1.为什么要替换:
c2.修改feign80模块:
1.POM修改:
<!-- httpclient5-->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
</dependency>
<!-- feign-hc5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
<version>13.1</version>
</dependency>
2.Apache HttpClient5配置开启说明:
- 1.关键配置:
# Apache HttpClient5 配置开启
spring:
cloud:
openfeign:
httpclient:
hc5:
enabled: true
- 2.YML配置完整:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connectTimeout: 4000 #连接超时时间
readTimeout: 4000 #读取超时时间
httpclient:
hc5:
enabled: true
#cloud-payment-service:
#connectTimeout: 4000 #连接超时时间
#readTimeout: 4000 #读取超时时间
d.替换前后的对比:
d1.替换前:
d2.替换后:
4.4.OpenFeign请求/响应压缩
a.官网说明:
b.OpenFeign请求/响应压缩是什么:
b1.对请求和响应进行GZIP压缩
- 1.Spring Cloud OpenFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
- 2.通过下面的两个参数设置,就能开启请求与相应的压缩功能:
spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true
b2.细粒度化设置
- 1.对请求压缩做一些更细致的设置,比如下面的配置内容指定压缩的请求数据类型并设置了请求压缩的大小下限,
- 2.只有超过这个大小的请求才会进行压缩:
spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json #触发压缩数据类型
spring.cloud.openfeign.compression.request.min-request-size=2048 #最小触发压缩的大小
c.YML文件配置
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
#cloud-payment-service:
#连接超时时间
connectTimeout: 4000
#读取超时时间
readTimeout: 4000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048 #最小触发压缩的大小
mime-types: text/xml,application/xml,application/json #触发压缩数据类型
response:
enabled: true
d.压缩效果:
- 1.压缩效果在下一节中的日志打印中进行体现
4.5.OpenFeign日志打印功能
a.日志打印功能:
- 1.Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节,说白了就是对Feign接口的调用情况进行监控和输出
b.日志级别:
- NONE
:默认的
,不显示任何日志; - BASIC:仅记录请求方法、URL、响应状态码及执行时间;
- HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
- FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。
c.配置日志bean
package com.atguigu.cloud.config;
import feign.Logger;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @auther zzyy
* @create 2023-04-12 17:24
*/
@Configuration
public class FeignConfig
{
@Bean
public Retryer myRetryer()
{
return Retryer.NEVER_RETRY; //默认
}
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
e.YML文件里需要开启日志的Feign客户端:
- 1.官网说明:
- 2.公式(三段):logging.level + 含有
@FeignClient注解的完整带包名的接口名
+debug
- 3.YML配置:
# feign日志以什么级别监控哪个接口 logging: level: com: atguigu: cloud: apis: PayFeignApi: debug
f.后台日志查看:
f1.带着压缩调用
f2.去掉压缩调用
g.重试机制的日志打印:
g1.类FeignConfig.java
package com.atguigu.cloud.config;
import feign.Logger;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig
{
@Bean
public Retryer myRetryer()
{
//最大请求次数为3(1+2),初始间隔时间为100ms,重试间最大间隔时间为1s
return new Retryer.Default(100,1,3);
}
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
g2.YML配置:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
#cloud-payment-service:
#连接超时时间
connectTimeout: 2000
#读取超时时间
readTimeout: 2000
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048
mime-types: text/xml,application/xml,application/json
response:
enabled: true
# feign日志以什么级别监控哪个接口
logging:
level:
com:
atguigu:
cloud:
apis:
PayFeignApi: debug
g3.测试:
g4.控制台打印:
h.完整的YML:
server:
port: 80
spring:
application:
name: cloud-consumer-openfeign-order
####Spring Cloud Consul for Service Discovery
cloud:
consul:
host: localhost
port: 8500
discovery:
prefer-ip-address: true #优先使用服务ip进行注册
service-name: ${spring.application.name}
openfeign:
client:
config:
default:
connectTimeout: 2000 #连接超时时间
readTimeout: 2000 #读取超时时间
httpclient:
hc5:
enabled: true
compression:
request:
enabled: true
min-request-size: 2048
mime-types: text/xml,application/xml,application/json
response:
enabled: true
#cloud-payment-service:
#connectTimeout: 4000 #连接超时时间
#readTimeout: 4000 #读取超时时间
# feign日志以什么级别监控哪个接口
logging:
level:
com:
atguigu:
cloud:
apis:
PayFeignApi: debug