转载声明 : 该文章出处为 扛麻袋的少年
本文目录:
写在开头
接上一篇文章:Spring Cloud 整合 Ribbon 实现服务调用(负载均衡)。我们已经知道: 引入 Ribbon 组件(在引入最新的 eureka 客户端依赖时,它默认已经帮我们集成了 Ribbon,此处并没有人为引入),同时配合 RestTemplate + @LoadBalance 注解
,就可以完成微服务之间 客户端 → 服务端调用 + (集群)服务的负载均衡
功能。
本文我们要介绍的 OpenFeign,也是一个来搞 服务调用 + 负载均衡
的组件 。Feign 是 Spring Cloud 组件中的一个轻量级 Restful 的 HTTP 服务客户端。随着 Feign 的停止更新,本文就直接从 OpenFeign 出发介绍。
说明:本文所说的 Feign 即 OpenFeign。OpenFeign 编写太长了,哈哈。Fiegn 和 OpenFeign 都差不多,OpenFeign 在 Feign 又作了一些修改封装,支持了 Spring MVC 的注解
1.Feign 和 OpenFeign 区别
Feign | OpenFeign |
---|---|
1.Feign 是 Spring Cloud 组件中的一个轻量级 Restful 的 HTTP 服务客户端 | 1.OpenFeign是 Spring Cloud 在 Feign 基础上进行的封装(Feign有的 OpenFeign都有,Feign没有的OpenFeign还有,哈哈) |
2.Feign 内置了Ribbon,用来做客户端负载均衡 ,去调用服务注册中心的服务; |
2.OpenFeign 支持了 Spring MVC 的注解 ,如@RequesMapping等;配合 Spring 开发,如虎添翼; |
3.Feign的使用方式是: 使用 Feign 的注解定义接口,调用这个接口,就可以调用服务注册中心的服务 |
3.OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并 通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务 |
4.Feign本身不支持Spring MVC的注解,它有一套自己的注解。(对比OpenFeign支持Spring MVC 注解,开发起来更香) |
4.在类名上,@RequesMapping 注解不能与 @FeignClient 注解同时使用 |
<depedency> <groupId>org.springframework.cloud<groupId> <artifacaId>spring-cloud-starter-feign</artifacaId> </dependency> |
<depedency> <groupId>org.springframework.cloud<groupId> <artifacaId>spring-cloud-starter-openfeign</artifacaId> </dependency> |
2.Feign 用在微服务客户端
Feign在消费端使用(官网有这样一句话:Declarative REST Client: Feign 声明式REST客户端:Feign)
SpringCloud 官网 OpenFeign 介绍:OpenFeign 官网介绍
3.有了Ribbon,为什么还要一个OpenFeign
Ribbon 和 OpenFeign 都可以 实现服务的调用
、实现负载均衡
。功能上来说,有冗余的嫌疑;但是活着就有它Feign 的意义。而且 OpenFeign 也内置了Ribbon,本文过后你就知道了 Feign 更符合开发流程,真香!!!
Feign 是一个声明式的 Web 客户端。使用 Feign 能让我们编写 Web 客户端更加简单。它只需要我们创建一个接口,并添加相对应的注解节课完成微服务之间的调用。
(这句话在这里不懂,继续向下了解就明白了,易懂)
3.1 OpenFeign 让开发变得容易
在使用 Ribbon + RestTemplate 时,利用 RestTemplate 对 HTTP 请求的封装处理,形成了一套模板化的调用方法。缺点:在每次进行服务调用时,都需要通过@Resource/@Autowired的方式,来声明一个 RestTemplate。
@RestController
@Slf4j
public class OrderController {
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
}
}
由于对服务依赖的调用可能不止一处,往往一个接口会被多出调用,所以通常都会针对每个微服务自行封装一些客户端类来保证这些依赖服务的调用。(类似封装所谓的工具类等方式,这样明显不能根治,多个消费者的话就需要各持一份,缺点太明显!!!)
所以,Feign 在此基础上做了进一步的封装,由它来帮助我们定义和实现依赖服务接口的定义。
在 Feign 的实现下,① 我们只需要创建一个接口
② 并使用注解的方式来配置它
,即可完成 对服务提供方的接口绑定
,简化了使用 Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。记住这两步就可以了。
大白话解释: 客户端 A 要调用 B 服务,Feign 就是在 A 中创建一个一模一样的接口B来对外提供服务的接口,我们调用 A 中的这个接口,就可以代用到服务 B 。(这也正好迎合了我们的 Controller → Service
的流程;没有 Feign 的话,我们在 Controller 不需要 Service 即可通过 RestTemplate 调用服务,还需要封装 RestTemplate 等,还不满足我们一般的开发流程)
Feign 真香定律!!!。尤其 OpenFeign 支持了 Spring MVC 注解,配合 Spring 进行项目开发,简直不要太爽。SpringCloud 官网 OpenFeign 介绍:OpenFeign 官网介绍
3.2 从此与 Ribbon 分手
在认识 Feign 之前,微服务之间调用。我们使用的是 Ribbon + RestTemplate
方式;从现在开始,我"爱上"了 OpenFeign,准备和 Ribbon 说分手了。
4.OpenFeign 在 Spring Cloud 中使用
4.1 在服务消费者操作
模块名称定义为:cloud-consumer-feign-order80
,来充当服务消费者的角色。
Ⅰ.引入pom.xml 依赖
<!-- 引入 spring-cloud-openfeign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Ⅱ.application.yml 配置文件修改
server:
port: 80
eureka:
client:
# 不将自己注册到 Eureka(注册与否自己决定,随便)
register-with-eureka: false
service-url:
# Eureka注册中心集群地址
defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
Ⅲ.主启动类,添加 @EnableFeignClients 注解支持
@SpringBootApplication
@EnableFeignClients //该注解的作用是扫描标记了@FeignClient的接口并创建实例bean,默认扫描并创建所在工程下的包
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class,args);
}
}
Ⅳ.消费端新建接口,并添加注解@FeignClient
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") //添加@FeignClient注解,指定服务提供方服务名称
public interface PaymentFeignService {
//OpenFeign支持Spring MVC注解,此处通过@GetMapping去调用 CLOUD-PAYMENT-SERVICE 该服务指定的接口
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id);//该接口声明必须和服务提供方一致
}
Ⅴ.为Fegin进行服务降级(兜底方法)
编写一个类,实现 PaymentFeignService 接口,并重写里面的方法,方法内容即为兜底方法。
public class PaymentFallbackFeignService implements PaymentFeignService {
@Override
public CommonResult getPaymentById(Long id) {
return new CommonResult(404, "OpenFeign兜底方法", new Payment(id, "errorSerial"));
}
}
Ⅵ.控制层controller
@RestController
public class OrderFeignController {
//此处就可以通过调用Service来完成 Controller → Service
//具体Service具体业务怎么调用,具体业务实现就由它随便实现吧
//这就是 OpenFeign 相比 RestTemplate 的好处
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
4.2 服务提供方 (服务提供方不需要操作,此处只用来展示相关内容)
Ⅰ.服务名称展示
Ⅱ.controller接口服务展示
5.OpenFeign测试
整合 OpenFeign 之后,我们在消费端通过URL: localhost/consumer/payment/get/31
发送请求,使用 OpenFeign 来实现服务调用,同时实现了负载均衡。测试动图如下:
OpenFeign 服务调用 + 负载均衡
相对 RestTemplate + Ribbon
来说,OpenFeign 用于 服务调用 + 负载均衡
,符合我们日常开发 Controller → Service
调用方式;同时可以省去对 RestTemplate 的封装
等等。
最终结果: OpenFeign 真香!!!在 服务调用 + 负载均衡
选择上,推荐使用 OpenFeign。
6.OpenFeign 超时控制
服务消费者在进行服务调用时,由于网络、查询效率 等问题,导致消费者不能及时获取返回数据,这就是 Feign 的超时控制。
默认 Feign 客户端只等待 1 秒钟
,但是服务端处理需要超过1秒钟,从而导致 Feign 客户端不再继续等待,直接以超时报错的方式返回
。为了避免这类情况,我们就需要设置 Feign 客户端的超时控制。
6.1 人为超时干预服务返回
同样的接口,此时我们人为睡眠 5s,此时服务消费者再次调用该服务,因为服务端处理需要超过 1 秒钟,从而导致 Feign 客户端直接以报错的方式返回。
6.2 设置 Feign 超时时间
此时需要在 客户端
进行 Feign 的超时时间配置,我们只需要在 application.yml 中配置 ribbon.ReadTimeout
和 ribbon.ConnectTimeout
两个属性,并设置允许的超时时间即可。
server:
port: 80
eureka:
client:
# 不将自己注册到 Eureka(注册与否自己决定,随便)
register-with-eureka: false
service-url:
# Eureka注册中心集群地址
defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
#设置feign客户端超时时间(OpenFeign集成了Ribbon,超时由ribbon控制)
ribbon:
#指的是建立连接后从服务器读取到可用资源所用的时间
ReadTimeout: 5000
#指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用的时间
ConnectTimeout: 5000
6.3 Feign超时生效测试
设置 Feign 超时时间为 5s,此时服务端睡眠修改为 3s。当再次发送请求时,我们可以观察到浏览器会等待 3s,当睡眠结束,在 Feign 允许的超时范围内,能够正常返回结果。
7.OpenFeign 日志打印功能
使用 Feign 进行服务间的调用,我们可以 使用 Feign 为我们提供的日志打印功能
,通过 配置日志级别
,来了解 Feign 中 Http 请求的细节。说白了就是 对Feign接口的调用情况进行监控和输出
7.1 Feign 日志级别
日志级别 | 说明 |
---|---|
NONE | 默认的,不显示任何日志 |
BASIC | 仅记录请求方法、URL、响应状态码、执行时间 |
HEADERS | 除了 BASIC 中定义的信息外,还有请求和响应的头信息 |
FULL | 除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据 |
7.2 设置 Feign 日志级别
1. 定义Feign 配置类
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
2. application.yml 配置日志输出级别
#配置日志输出级别
logging:
level:
com.study.springcloud.service.PaymentFeignService: debug
3. Feign日志输出
本文代码下载地址:Spring Cloud 整合 OpenFeign 实现服务调用 (提取码:mnh4)
下一篇:Spring Cloud 整合 Hystrix 实现服务降级、服务熔断、服务限流