跟乐乐学微服务!(四)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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听