跟乐乐学微服务!(四)Spring Cloud组件 Feign

2023-11-01 12:10

本文主要是介绍跟乐乐学微服务!(四)Spring Cloud组件 Feign,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇文章:跟乐乐学微服务!(三)SpringCloud组件熔断器 Hystrix

Feign是什么?

Feign可以对服务提供方所暴露的url请求地址进行拼接封装,然后伪装成一个接口的方法,消费方可以通过调用这个Feign伪装了的接口方法,去请求服务提供方。
这是为了让消费方Controller调用提供方暴露的接口时,能够看上去像MVC架构中从Controller去调用Service一样。
是的,说到‘伪装‘,Feign的英文意思叫伪装,事实上它在Cloud微服务中最大的作用就是伪装成方法去调用服务提供方。
同时,Feign也集成了Ribbon负载均衡
,这是因为当服务消费方通过Feign伪装了的接口方法去请求服务提供方时,会自动进行负载均衡。
此外,Feign还集成了Hystrix熔断器。

Feign应用:伪装

Feign伪装概念

在没有Feign之前,服务消费方要访问提供方所暴露的接口的话,
服务消费方需要在controller层,根据服务提供方的服务名和接口路径来拼接成一个url,接着通过restTemplate对象来访问。
但是通过Feign的话,消费方可以通过调用一个接口(使用了FeignClient注解)的方法,直接去访问服务提供方的接口。
这么做的好处在于,能够隐藏向提供方发起的Rest请求,伪装成SpringMVC架构这种、直接调用Service层接口的风格。
在这里插入图片描述

Feign伪装实现

在这里插入图片描述

  • 先在消费方引入Feign的依赖
        <!-- Feign依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
  • 在消费方的SpringBoot启动类中,加入@EnableFeignClients注解,声明使用Feign组件。

在这里插入图片描述

  • 创建一个用于伪装的接口,有两点需要注意。
    1.接口上面使用@FeignClient注解指定一个用于请求的服务提供方的服务名。
    2.接口方法必须为Rest风格定义,因此要有@GetMapping或@PostMapping等注解(和服务提供方一致),Rest请求注解内的value值便是提供方所暴露接口的路径。
package com.databasequery.databasequeryconsumer.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "database-provider-service")//value值为服务提供方的服务名
public interface ProviderServiceFeign {@GetMapping(value = "/query/qq/{qqnum}")//value为服务提供方暴露的接口路径。Rest注解也需要和服务提供方的接口保持一致。Object qqQuery(@PathVariable("qqnum") String qq);}
  • 接下来在消费方的Controller中,通过@Autowired注解注入这个接口(如果注入爆红,则无视),然后定义一个新的消费方法’qqQueryFeign’,这个方法不再通过restTemplate对象进行请求,改为直接调用feign伪装接口的的方法。
@RestController
@RequestMapping(value = "query")
@DefaultProperties(defaultFallback = "defaultFallbach") //指定当前类的全局服务降级方法
public class QueryController {// restTemplate用于访问服务提供方暴露的接口。@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate ProviderServiceFeign providerServiceFeign;//直接调用Fegin伪装接口的方法来请求服务提供方的接口。@HystrixCommand@GetMapping("qqQueryFeign/{qqNumber}")public Object qqQueryFeign(@PathVariable("qqNumber") String qqNumber){return providerServiceFeign.qqQuery(qqNumber);}@HystrixCommand@GetMapping("qq/{qqNumber}")public Object qqQuery(@PathVariable("qqNumber") String qqNumber){System.out.println("收到一条查询请求,被查账号是:"+qqNumber);String url = "http://database-provider-service/query/qq/"+qqNumber;Object qr =   restTemplate.getForObject(url, Object.class);return qr;}public Object defaultFallbach(){String responseErrorStr = "不好意思,服务正忙,请您稍后再试!--- 来自全局默认的降级方法";return responseErrorStr;}
}
  • 接下来,我们尝试访问消费服务方。成功响应。

在这里插入图片描述

Feign内置集成应用:Ribbon负载均衡

介绍

不知道你有注意到没,我们在消费方和提供方的耦合这一点上,是通过在接口上声明 @FeignClient(value = “提供方的服务名称”) 注解来实现的。
我们并没有从eureka服务端拉取过来的服务列表中选择其中的某个服务。
是不是感觉有点熟悉呢?
没错,这是Feign它自身已经集成了Ribbon来实现负载均衡的缘故。

关于Eureka和Feign各自都有集成Ribbon这一点

但是,在我的微服务第二篇博客文章SpringCloud组件负载均衡Ribbon的应用中,我提到了Eureka客户端集成了Ribbon;那么,既然Feign也集成了Ribbon,他们会冲突吗?
答案是并不会发生冲突
不过需要注意的是,当使用了Feign后,application.yml中ribbon的配置参数,将会只对调用了Feign伪装接口的消费者controller层方法起作用
并不会对使用RestTemaplte对象进行负载均衡请求的消费者controller层方法起作用。
为了确认这一点,我们可以进行一个演示。

  1. 配置负载均衡

前面说到,使用了Feign组件的情况下,配置文件中的ribbon参数将会只对调用了feign接口的controller层方法起作用;
为了证明,我们在消费方的appilication.yml配置文件中,对Ribbon进行配置。
ribbon的默认超时是1秒,那么参数中我们指定为100毫秒。

ribbon:ReadTimeout: 100 # 读取超时时长。默认1秒。衡量的是消费方和提供方建立连接后,从读取资源到响应回消费方本地所耗费的时长。为方便验证,这里改为100毫秒ConnectTimeout: 100 # 建立链接的超时时长,默认1秒。衡量的是消费方和提供方建立连接所耗费的时长。为方便验证,这里改为100毫秒OkToRetryOnAllOperations: false # 默认为true,是否对所有的请求重试。MaxAutoRetries: 0 # 表示当消费方访问提供方实例出错后,对同一个提供方实例所进行的重试次数。默认为1。为方便验证,这里改为0MaxAutoRetriesNextServer: 0 # 当对同一个提供方实例的重试达到了规定次数后,会自动更换另一个实例进行请求;此处设置的是更换实例的次数。默认为2。为方便验证,这里改为0
  1. 更改服务提供方的逻辑
    在提供方controller层的某个方法内,加一个延时逻辑,以演示出 Eureka内置的ribbon负载均衡(RestTemaplte对象) 和 Feign内置的ribbon负载均衡(调用伪装接口) 遇到超时情况,哪一方会依照application.yaml文件中的ribbon配置参数去处理。
@RestController
@RequestMapping(value = "query")
public class QueryController {@Autowiredprivate QueryService queryService;@GetMapping("qq/{qqnum}")public QueryResult qqQueryMethod(@PathVariable("qqnum") String qqnum){try {Thread.sleep(500);//延时500毫秒} catch (InterruptedException e) {e.printStackTrace();}QueryResult query = queryService.query(qqnum);return query;}
}
  1. 得出结果

现在我们分别访问两个地址:
http://127.0.0.1:8082/query/qqQueryFeign/980199757 使用feign伪装的接口调用。
http://127.0.0.1:8082/query/qq/980199757 使用RestTemaplte对象调用。
在这里插入图片描述
可以看到,左侧等待了500毫秒后(ribbon默认最大超时1秒),成功响应了数据给前端。而右侧则是被进行了降级处理(配置文件中设置的最大超时为100毫秒)。
这说明,在使用了Eureka和Feign的情况下,application.yml文件中的Ribbon负载均衡配置,只Feign所集成的Ribbon组件起作用。而非对Eureka所集成的Ribbon组件起作用。

Feign内置集成应用:Hystrix熔断器

在这里插入图片描述

介绍

Feign内部也集成了Hystrix熔断器。但是它的实现过程和我的上一篇文章跟乐乐学微服务!(三)SpringCloud组件熔断器 Hystrix中所介绍的不同。
它需要一个实现类去实现Feigon伪装接口(之前的ProviderServiceFeign.class),重写它的方法(qqQuery),然后这个重写的方法体就是用于处理服务降级的方法。

实现

  1. Feign尽管内部集成了Hystrix,但默认是不开启状态的,所以需要先在配置文件中声明开启。
feign:hystrix:enabled: true # 声明feign内部集成的hystrix为开启状态。默认为关闭。
  1. 创建实现类去实现Feign伪装接口,去重写方法。该类和重写的方法将作为对应请求的服务降级方法。
@Component // 必须要使用@Compoent将实现类交由Spring管理。否则Controller层无法调用接口。
public class ProviderServiceFeignImpl implements ProviderServiceFeign {@Overridepublic Object qqQuery(String qq) {return "查询正忙! 来自Fengin内置Hystirx组件的降级处理。";}
}
  1. 在Feign伪装接口的@FeignClient注解中,通过fallback属性指定它的实现类为服务降级处理类。

在这里插入图片描述

  1. 为了能够触发熔断机制,使得用户请求被降级处理,我们更改一下服务提供方中controller层的逻辑。
@RestController
@RequestMapping(value = "query")
public class QueryController {@Autowiredprivate QueryService queryService;@GetMapping("qq/{qqnum}")public QueryResult qqQueryMethod(@PathVariable("qqnum") String qqnum){if (qqnum.equals("99999")){// 如果传入的参数是这个,就报异常。throw new RuntimeException("异常。。。");}QueryResult query = queryService.query(qqnum);return query;}
}
  1. 请求消费方,消费方调用Feign伪装的接口后,因为提供方抛出了异常,所以请求被Feign内置的hystrix熔断器进行降级方法处理了。
    在这里插入图片描述

关于独立引用Hystrix和Feign内置Hystirx

假如说,我们之前已经根据上一篇文章跟乐乐学微服务!(三)SpringCloud组件熔断器 引入了独立版本的Hystrix依赖。现在又使用Feign内置的Hystrix的话,会不会有冲突呢?
答案是:不会有冲突。
假如,用户所请求的消费方Controller层的方法内,是调用了Feign伪装的接口去请求提供方的话,那么将会使用Feign内置的Hystrix;如果需要降级处理,是让Feign伪装接口的实现类中的方法去处理。

假如,用户所请求的服务消费方Controller层的方法内,是通过RestTemaplte对象请求提供方的话。那么将会使用独立的Hystrix组件;如果需要降级处理的话,也是通过@HystrixCommand或@DefaultProperties注解所指定的方法去处理降级。
通过下面的图解,可以验证。
在这里插入图片描述

Feign应用:Gzip压缩

Feign可以将 请求 和 响应 的数据通过Gzip进行压缩,以此来减少数据交互过程中的性能损耗从而提高效率。

  • 开启request数据压缩,默认为false。

feign.compression.request.enabled=true

  • 设置要压缩的数据类型。默认为text/html,application/xml,application/json

feign.compression.request.mime-types=text/html,application/xml,application/json

  • 设置触发压缩请求数据的大小上线。默认值为2048(kb)
    feign.compression.request.min-request-size=2048

  • 开启response数据压缩,默认为false。
    feign.compression.response.enabled=true

转换为Yaml格式后如下:

feign:compression:request:enabled: true # 开启request数据压缩,默认为false。mime-types: text/html,application/xml,application/json # 要压缩的数据类型。此为默认值。min-request-size: 2048 # 触发压缩的大小上线。此为默认值(2mb)。response:enabled: true # 开启response数据压缩。默认为false。

Feign应用:日志级别设置

Feign也可以进行日志记录,不过需要创建一个配置类,然后将该类实例化为一个Bean给IOC容器管理,才能实现日志记录功能。

  1. 首先在消费方的application.yml进行日志参数配置。

其中需要指定一个包路径,这个路径一般涵盖了消费方的Controller层路径,或者还涵盖了Service,Dao这三层;这代表对该路径下的所有类发生的操作进行日志记录。
日志级别指定为debug

logging:level:com.databasequery.databasequeryconsumer: debug # 对com.databasequery.databasequeryconsumer包路径进行日志记录 日志级别为debug。

在这里插入图片描述

  1. 创建Feign的配置类,并在其中创建用于指定日志级别的方法,将该方法通过@Bean实例化。

日志级别有以下四个:

 * NONE:不记录任何日志信息,这是默认值。* BASIC:仅记录请求的方法,URL以及响应状态码和执行时间* HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息* FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*** Feign的配置类。主要用于配置*/
@Configuration
public class FeignConfig {/*** 此处返回Feign的日志记录等级。* @return*/@BeanLogger.Level logLevelInfo(){return Logger.Level.FULL;}}
  1. 在Feign伪装接口,通过@FeignClient注解的configuration属性,指定其Feign配置类。
    在这里插入图片描述
  2. 一切配置好后,我们启动服务并尝试访问一下,能够看到可以输出用户的访问信息了。
    在这里插入图片描述
    不过要注意的是,只会对调用了feign伪装接口的请求进行日志记录,并不会对使用RestTemplate对象去调用提供方的请求进行记录。

这篇关于跟乐乐学微服务!(四)Spring Cloud组件 Feign的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/322865

相关文章

SpringBoot中四种AOP实战应用场景及代码实现

《SpringBoot中四种AOP实战应用场景及代码实现》面向切面编程(AOP)是Spring框架的核心功能之一,它通过预编译和运行期动态代理实现程序功能的统一维护,在SpringBoot应用中,AO... 目录引言场景一:日志记录与性能监控业务需求实现方案使用示例扩展:MDC实现请求跟踪场景二:权限控制与

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

Java controller接口出入参时间序列化转换操作方法(两种)

《Javacontroller接口出入参时间序列化转换操作方法(两种)》:本文主要介绍Javacontroller接口出入参时间序列化转换操作方法,本文给大家列举两种简单方法,感兴趣的朋友一起看... 目录方式一、使用注解方式二、统一配置场景:在controller编写的接口,在前后端交互过程中一般都会涉及

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Maven中引入 springboot 相关依赖的方式(最新推荐)

《Maven中引入springboot相关依赖的方式(最新推荐)》:本文主要介绍Maven中引入springboot相关依赖的方式(最新推荐),本文给大家介绍的非常详细,对大家的学习或工作具有... 目录Maven中引入 springboot 相关依赖的方式1. 不使用版本管理(不推荐)2、使用版本管理(推

Java 中的 @SneakyThrows 注解使用方法(简化异常处理的利与弊)

《Java中的@SneakyThrows注解使用方法(简化异常处理的利与弊)》为了简化异常处理,Lombok提供了一个强大的注解@SneakyThrows,本文将详细介绍@SneakyThro... 目录1. @SneakyThrows 简介 1.1 什么是 Lombok?2. @SneakyThrows