当前位置:网站首页>OpenFeign 服务接口调用
OpenFeign 服务接口调用
2022-07-04 08:12:00 【喵先森爱吃鱼】
一、概述
1.1 Feign 介绍
Feign 是 Netflix 开发的声明式,模板化的 HTTP 客户端,其灵感来自 Retrofit,JAXRS-2.0 以及 WebSocket。
- Feign 可帮助我们更加便捷,优雅的调用 HTTP API。
- 在 SpringCloud 中,使用 Feign 非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。
- Feign 支持多种注解,例如 Feign 自带的注解或者 JAX-RS 注解等。
- SpringCloud 对 Feign 进行了增强,使 Feign 支持了 SpringMVC 注解,并整合了 Ribbon 和 Eureka,从而让 Feign 的使用更加方便。
官网:https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
GitHub:https://github.com/spring-cloud/spring-cloud-openfeign
1.2 Feign 的作用
Feign 旨在使编写 Java Http 客户端变得更容易。
前面在使用 Ribbon + RestTemplate 时,利用 RestTemplate 对 Http 请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务以来的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign 在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在 Feign 的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是 DAO 接口上面标注 @Mapper 注解,现在是一个微服务接口上面标注一个 Feign 注解即可),即可完成对服务提供方的接口绑定,简化了使用 SpringCloud Ribbon 时,自动封装服务调用客户端的开发量。
Feign 集成了 Ribbon,利用 Ribbon 维护了服务提供者的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与 Ribbon 不同的是,通过 Feign 只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
1.3 Feign 和 OpenFeign 的区别
Feign | OpenFeign |
---|---|
Feign 是 SpringCloud 组件中的一个轻量级 RESTful 的 HTTP 服务客户端。Feign 内置了 Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign 的使用方式是:使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。 | OpenFeign 是 SpringCloud 在 Feign 的基础上支持了 SpringMVC 的注解 @RequestMapping 等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。 |
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter- feign</artifactId> </dependency> | <dependency> <groupId>org.springframework.cloud</ groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> |
二、基于 OpenFeign 的服务调用
2.1 引入依赖
<?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">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-feign-order80</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
2.2 配置 application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
2.3 配置主启动类,并添加 Feign 的支持
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class, args);
}
}
通过 @EnableFeignClients
注解开启 SpringCloud Feign 的支持功能。
2.4 启动类激活 FeignClient
创建一个 Feign 接口,此接口是在 Feign 中调用微服务的核心接口。
在服务消费者 cloud-consumer-feign-order80 中创建一个 PaymentFeignService 接口并新增注解@FeignClient
@Service
@FeignClient(name = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
@GetMapping(value = "/payment/get/{id}")
CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
- 定义各参数绑定时,@PathVariable、@RequestParam、@RequestHeader 等可以指定参数属性,在 Feign 中绑定参数必须通过 value 属性来指明具体的参数名,不然会抛出异常。
- @FeignClient 注解通过 name 指定需要调用的微服务的名称,用于创建 Ribbon 的负载均衡器。所以 Ribbon 会把 CLOUD-PAYMENT-SERVICE 解析为注册中心的服务。
2.5 配置请求提供者的调用接口
@RestController
@Slf4j
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
2.6 测试
先启动2个eureka集群7001/7002,再启动2个微服务8001/8002,最后启动OpenFeign
访问 http://localhost/consumer/payment/get/31
可以看出 Feign 自带负载均衡配置项。Feign 中本身已经集成了 Ribbon 依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册 RestTemplate 对象。另外,如果想要修改 Ribbon 的配置,仍然可以通过 ribbon.xx
来进行全局配置。也可以通过 服务名.ribbon.xxx
来对指定服务进行配置。
2.7 总结
三、Feign 和 Ribbon 的联系
Ribbon 是一个基于 HTTP 和 TCP 客户端的负载均衡的工具,它可以在客户端配置 RibbonServerList(服务端列表),使用 HttpClient 或 RestTemplate 模拟 http 请求,步骤相当繁琐。
Feign 是在 Ribbon 的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的方式,只需要创建一个接口,然后在上面添加注解,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建 http 请求。在调用时就像是调用自身工程的方法,而感觉不到是调用远程方法,使得编写客户端变得非常容易。
四、超时控制
Feign 客户端在调用服务端时,默认等待程序执行的时间为 1 秒钟,超时则会报错。但是一般服务端处理可能会超过 1 秒钟,为了避免这种情况,我们需要设置 Feign 客户端的超时控制。
4.1 演示超时报错
4.1.1 服务提供方 8001 和 8002 添加暂停程序
将下面的代码添加进 8001 和 8002 的 PaymentController 类中:
@GetMapping("/payment/feign/timeout")
public String paymentFeignTimeOut(){
System.out.println("*****************paymentFeignTimeOut from serverPort:" + serverPort);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e){
e.printStackTrace();
}
return serverPort;
}
4.1.2 服务消费方 80 添加超时方法
在 PaymentFeignService 中添加下面的代码:
@Service
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
@GetMapping(value = "/payment/feign/timeout")
String paymentFeignTimeOut();
}
在 OrderFeignController 中添加下面的代码:
@RestController
@Slf4j
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/payment/feign/timeout")
public String paymentFeignTimeOut(){
return paymentFeignService.paymentFeignTimeOut();
}
}
4.1.3 测试
访问 http://localhost/consumer/payment/feign/timeout
4.2 开启超时控制
4.2.1 第一种方式
修改 application.yml 文件,添加如下配置
# 设置 feign 客户端超时时间(OpenFeign默认支持 ribbon )
ribbon:
# 指的是建立连接所用的时间,适用于网络状况正常的情况下 , 两端连接所用的时间
ReadTimeout: 5000
# 指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
80 完整的 application.yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
# 设置 feign 客户端超时时间(OpenFeign默认支持 ribbon )
ribbon:
ReadTimeout: 5000 # 指的是建立连接所用的时间,适用于网络状况正常的情况下 , 两端连接所用的时间
ConnectionTimeout: 5000 # 指的是建立连接后从服务器读取到可用资源所用的时间
4.2.2 第二种方式:
修改 application.yml 文件,添加如下配置
feign:
client:
config:
CLOUD-PAYMENT-SERVICE:
readTimeout: 5000
connectTimeout: 5000
80 完整的 application.yml:
server:
port: 80
spring:
application:
name: cloud-feign-consumer
eureka:
client:
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
feign:
client:
config:
CLOUD-PAYMENT-SERVICE: # FeignClient的名称
readTimeout: 5000
connectTimeout: 5000
添加完成后重启 80 进行测试:
4.3 Feign 的其他配置
从 SpringCloud Edgware 开始,Feign支持使用属性自定义 Feign。对于一个指定名称的 FeignClient(例如该 FeignClient 的名称为 feignName),Feign 支持如下配置项:
feign:
client:
config:
feignName: # 定义 FeignClient 的名称
readTimeout: 5000
connectTimeout: 5000
# 配置 Feign 的日志级别,相当于代码配置方式中的 Logger
loggerLevel: FULL
# Feign 的错误解码器,相当于代码配置方式中的 ErrorDecoder
errorDecoder: com.example.SimpleErrorDecoder
# 配置重试,相当于代码配置方式中的 Retryer
retryer: com.example.SimpleRetryer
# 配置拦截器,相当于代码配置方式中的 RequestInterceptor
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
- feignName:FeignClient 的名称
- connectTimeout:建立链接的超时时长
- readTimeout:读取超时时长
- loggerLevel:Feign 的日志级别
- errorDecoder:Feign 的错误解码器
- retryer:配置重试
- requestInterceptors:添加请求拦截器
- decode404:配置熔断不处理404异常
4.4 日志打印功能
在开发或者运行阶段往往希望看到 Feign 请求过程的日志记录,默认情况下 Feign 的日志是没有开启的。开启方式有两种:一种是通过配置 yml 方式开启,另一种是通过配置类开启。
4.4.1 配置 application.yml
要想用属性配置方式来达到日志效果,只需要在 application.yml 中添加如下内容即可:
feign:
client:
config:
CLOUD-PAYMENT-SERVICE: # 定义 FeignClient 的名称
# 配置 Feign 的日志级别,相当于代码配置方式中的 Logger
loggerLevel: FULL
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug
loggin.level.xx: debug
: feign 日志以什么级别监控哪个接口feign.client.config.CLOUD_PAYMENT_SERVICE.loggerLevel
:配置 Feign 的日志级别。
Feign 有四种日志级别:
- NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
- BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态码以及执行时间
- HEADERS:记录 BASIC 级别的基础上,记录请求和响应的 header
- FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的 header、body 和元数据。
完整的 application.yml
server:
port: 80
spring:
application:
name: cloud-feign-consumer
eureka:
client:
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
feign:
client:
config:
CLOUD-PAYMENT-SERVICE: # 定义 FeignClient 的名称
readTimeout: 5000
connectTimeout: 5000
# 配置 Feign 的日志级别,相当于代码配置方式中的 Logger
loggerLevel: FULL
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug
4.4.2 配置类
1、创建配置类
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
2、yml 配置文件开启日志功能
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug
完整的 application.yml:
server:
port: 80
spring:
application:
name: cloud-feign-consumer
eureka:
client:
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
# 设置 feign 客户端超时时间(OpenFeign默认支持 ribbon )
ribbon:
ReadTimeout: 5000 # 指的是建立连接所用的时间,适用于网络状况正常的情况下 , 两端连接所用的时间
ConnectionTimeout: 5000 # 指的是建立连接后从服务器读取到可用资源所用的时间
logging:
level:
com.atguigu.springcloud.service.PaymentFeignService: debug # feign 日志以什么级别监控哪个接口
启动测试,访问http://localhost/consumer/payment/get/31
边栏推荐
- Li Kou today's question -1200 Minimum absolute difference
- Leetcode (215) -- the kth largest element in the array
- How to use C language code to realize the addition and subtraction of complex numbers and output structure
- zabbix监控系统邮件报警配置
- NPM run build error
- deno debugger
- Parallel shift does not provide any acceleration - C #
- 真空介电常数和真空磁导率究竟是由什么决定的?为何会存在这两个物理量?
- @Role of requestparam annotation
- Activiti common operation data table relationship
猜你喜欢
【性能測試】一文讀懂Jmeter
Système de surveillance zabbix contenu de surveillance personnalisé
PCIe knowledge points -010: where to get PCIe hot plug data
Fault analysis | MySQL: unique key constraint failure
What sparks can applet container technology collide with IOT
DM8 tablespace backup and recovery
Unity-Text上标平方表示形式+text判断文本是否为空
【性能测试】一文读懂Jmeter
Collections in Scala
弈柯莱生物冲刺科创板:年营收3.3亿 弘晖基金与淡马锡是股东
随机推荐
Thesis learning -- time series similarity query method based on extreme point characteristics
@Role of requestparam annotation
Const string inside function - C #
BUUCTF(4)
This monitoring system can monitor the turnover intention and fishing all, and the product page has 404 after the dispute appears
What sparks can applet container technology collide with IOT
DM8 command line installation and database creation
Do you know about autorl in intensive learning? A summary of articles written by more than ten scholars including Oxford University and Google
C # implements a queue in which everything can be sorted
学习Nuxt.js
string. Format without decimal places will generate unexpected rounding - C #
1. Kalman filter - the best linear filter
Activiti常见操作数据表关系
Moher College phpmailer remote command execution vulnerability tracing
Wechat has new functions, and the test is started again
Preliminary study on temporal database incluxdb 2.2
Leetcode (215) -- the kth largest element in the array
JVM中堆概念
1、卡尔曼滤波-最佳的线性滤波器
ES6 summary