1. Feign简介
1.1 简介
Feign是Netflix公司开发的一个声明式的REST调用客户端; Ribbon负载均衡、 Hystrⅸ服务熔断是我们Spring Cloud中进行微服务开发非常基础的组件,在使用的过程中我们也发现它们一般都是同时出现的,而且配置也都非常相似,每次开发都有很多相同的代码,因此Spring Cloud基于Netflix Feign整合了Ribbon和Hystrix两个组件,让我们的开发工作变得更加简单, 就像Spring boot是对Spring+ SpringMVC的简化, Spring Cloud Feign对Ribbon负载均衡、 Hystrⅸ服务熔断进行简化,在其基础上进行了进一步的封装,不仅在配置上大大简化了开发工作,同时还提供了一种声明式的Web服务客户端定义方式。使用方式类似Dubbo的使用方式。
1.2 Feign和Ribbon的联系
Ribbon是一个基于 HTTP 和 TCP 客户端 的负载均衡的工具。它可以 在客户端配置
RibbonServerList(服务端列表),使用 HttpClient 或 RestTemplate 模拟http请求,步骤相当繁琐。
Feign 是在 Ribbon的基础上进行了一次改进,是一个使用起来更加方便的 HTTP 客户端。采用接口的 方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方 法即可, 不需要自己构建http请求。然后就像是调用自身工程的方法调用,而感觉不到是调用远程方 法,使得编写客户端变得非常容易。
1.3 负载均衡
Feign中本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册 RestTemplate 对象。
2. 能干什么
feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
3. Quick Start
3.1 创建服务注册中心
3.1.1 引入依赖坐标
3.1.2 配置application.yml
3.1.3 配置启动类
添加@EnableEurekaServer 标记为EurekaServer
3.1.4 启动项目
浏览器输入
localhost:8080
访问注册中心
3.2 创建服务提供者
3.2.1 引入依赖坐标
3.2.2 配置application.yml
这里将port设置为动态传参,主要是想通过设置vm参数来使启动两个端口不同的服务,以便后续通过consumer调用的时候实现负载均衡效果
3.2.3 创建测试接口
3.2.4 配置启动项
通过idea的复制功能创建两个启动模板,且8011模板通过传port参数实现服务端口的动态替换
3.2.5 启动服务
查看注册中心控制台
服务已注册成功
测试服务接口
3.3 创建服务消费者
3.3.1 引入坐标依赖
这里之所以将全部的依赖都展示
因为Netflix 公司2018年已经宣布停止Hystrix的维护,导致springcloud的最新版本即:
2020.0.1
已经完全废弃了Hystrix
文档链接为:Resilience4J
所以如果要使用Hystrix需使用
Hoxton.SR10
及以下版本 Hoxton.SR10对应其他服务的版本
3.3.2 配置application.yml
3.3.3 配置启动类
通过EnableFeignClients开启服务对feign的支持
3.3.4 创建测试接口
创建测试访问接口
@FeignClient:
- name:指定需要调用的微服务的名称(不分大小写),用于创建Ribbon的负载均衡器。 所以Ribbon会把
provider
解析为注册中心的服务。- fallback:指定请求失败时的回退逻辑
请求失败回退处理
3.3.5 启动项目
查看注册中心控制台
服务注册已成功
测试接口
第一次访问:
第二次访问:
测试请求服务超时
打印堆栈信息如下:
当直接把服务提供者关闭后,请求返回结果也是熔断返回的信息,符合预期。
4. 客户端Hystrix整合
springcloud每个版本的差异比较大,有的低版本可能需要显性的引用hystrix依赖
当前使用的
Hoxton.SR10
版本不需要引用,因为已经被feign整合了
4.1 熔断器使用
在网络请求时,可能会出现异常请求,如果还想再异常情况下使系统可用,那么就需要容错处理,比如:网络请求超时时给用户提示“稍后重试”或使用本地快照数据等等。
Spring Cloud Feign就是通过Fallback
实现的,有两种方式:
- @FeignClient.fallback = xxxFeignFallback.class指定一个实现Feign接口的实现类。
- @FeignClient.fallbackFactory = xxxFeignFactory.class指定一个实现FallbackFactory工厂接口类
注意:feign的注解@FeignClient:fallbackFactory与fallback方法不能同时使用,这个两个方法其实都类似于Hystrix的功能,当网络不通时返回默认的配置数据。
4.2 配置文件配置
在application.properties 启用hystrix
请务必注意,从Spring Cloud Dalston开始,Feign默认是不开启Hystrix的。
因此,如使用Dalston以及以上版本请务必额外设置属性:feign.hystrix.enabled=true,否则 断路器不会生效。
Spring Cloud Angel/Brixton/Camden中,Feign默认都是开启Hystrix的。
4.3 fallback 实现
创建HelloFallbackImpl的回调实现,由spring创建使用@Component(其他的注册也可以)注解
HystrixTargeter.targetWithFallback方法实现了@FeignClient.fallback处理逻辑,通过源码可以知道HelloFallbackImpl回调类是从Spring容器中获取的,所以HelloFallbackImpl由spring创建。
4.3.1 HelloService 接口类
4.3.2 HelloFallbackImpl回退类
4.3.3 验证
关闭服务提供者后测试
4.4 FallbackFactory工厂
上面的实现方式简单,但是获取不到HTTP请求错误状态码和信息 ,这时就可以使用工厂模式来实现Fallback
同样工厂实现类也要交由spring管理。
4.4.1 HelloService 接口类
fallbackFactory 属性 指定了 自定义的回退工厂
4.4.2 HelloFallbackFactory回退类
注意 实现的是
feign.hystrix.FallbackFactory
4.4.3 验证
关闭服务提供者后测试
5. 自定义ErrorDecoder
ErrorDecoder
接口处理请求错误信息,默认实现ErrorDecoder.Default
抛出FeignException
异常
FeignException.status
方法返回HTTP状态码,FallbackFactory.create
默认情况下可以强制转换成FeignException
异常这样就可以获取到HTTP状态码了。
5.1 FeignErrorDecoder
自定义FeignErrorDecoder
消费者提供请求报错的方法,供调用者调用
5.2 流程
在Feign客户端发生http请求层面(提供者业务代码报错)的错误时会调用decode方法。在decode方法中实现自定义的错误处理,当出现异常时首先会通过FeginErrorDecoder
进行异常的封装,然后会调用HelloFallbackFactory
进行异常的回调处理
消费者调用结果如下
6. 扩展
6.1 Feign使用HttpClient
Feign在默认情况下使用的是JDK原生URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection。我们可以用Apache的HTTP Client替换Feign原始的http client,从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud从Brixtion.SR5版本开始支持这种替换。
6.1.2 导入POM依赖
6.1.3 配置文件配置
主要:这个配置可加可不加,在该版本中默认为true,可以不加,在HttpClientFeignLoadBalancedConfiguration源码中有的配置默认为true
6.1.4 验证
首先在工程配置文件中,将配置项 feign.httpclient.enabled 的值,设置为 false 。然后,在HttpClientFeignLoadBalancedConfiguration 的 feignClient(…)方法内的某行打上断点,重新启动项目,注意观察会发现,整个启动过程中,断点没有被命中。接下来,将配置项 feign.httpclient.enabled 的值设置为 true,再一次启动项目,断点被命中。由此,可以验证 HttpClientFeignLoadBalancedConfiguration 自动配置类被启动。
6.2 在feign请求之前操作
feign组件提供了请求操作接口RequestInterceptor,实现之后对apply函数进行重写就能对request进行修改,包括header和body操作。
6.3 请求压缩
Spring Cloud Feign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。我们只需通过下面两个参数设置,就能开启请求与响应的压缩功能:
同时,我们还能对请求压缩做一些更细致的设置,比如下面的配置内容指定了压缩的请求数据类型,并设置了压缩的大小下限,只有超过这个大小的请求才会对其进行压缩。
上述配置的feign.compression.request.nime-types和feign.compression.requestmin-request-size均为默认值。
6.4 日志配置
Spring Cloud Feign在构建被@FeignClient注解修饰的服务客户端时,会为每一个客户端都创建一个feign的请求细节。可以在application.properties文件中使用logging.level.
但是,只是添加了如上配置,还无法实现对DEBUG日志的输出。这时由于Feign客户端默认对Logger.Level对象定义为NONE级别,该界别不会记录任何Feign调用过程中对信息,所以我们需要调整它对级别,针对全局对日志级别,可以在应用主类中直接假如Logger.Level的Bean创建,具体如下:
在调整日志级别为FULL之后,我们调用接口测试,查看日志
6.4.1 fegin日志级别
对于Feign的Logger级别主要有下面4类,可根据实际需要进行调整使用。
NONE:不记录任何信息。
BASIC:仅记录请求方法、URL以及响应状态码和执行时间。
HEADERS:出了记录BASIC级别的信息之外,还会记录请求和响应的头信息。
FULL:记录所有请求与响应的细节,包括头信息、请求体、元数据等。
7. FeignClient注解的一些属性
属性名 | 默认值 | 作用 | 备注 |
---|---|---|---|
value | 空字符串 | 调用服务名称,和name属性相同 | |
serviceId | 空字符串 | 服务id,作用和name属性相同 | 已过期 |
name | 空字符串 | 调用服务名称,和value属性相同 | |
contextId | 空字符串 | 参考下方介绍 | |
url | 空字符串 | 全路径地址或hostname,http或https可选 | url用于配置指定服务的地址,相当于直接请求这个服务,不经过Ribbon的服务选择。 |
decode404 | FALSE | 配置响应状态码为404时是否应该抛出FeignExceptions | |
configuration | {} | 自定义当前feign client的一些配置 | 参考FeignClientsConfiguration |
fallback | void.class | 熔断机制,调用失败时,走的一些回退方法,可以用来抛出异常或给出默认返回数据。 | 底层依赖hystrix,启动类要加上@EnableHystrix |
fallbackFactory | void.class | 和fallback功能相似,只不过fallbackFactory中有报错的Throwable信息 | |
path | 空字符串 | 自动给所有方法的requestMapping前加上前缀,类似与controller类上的requestMapping | |
primary | TRUE | primary对应的是@Primary注解,默认为true,官方这样设置也是有原因的。当我们的Feign实现了fallback后,也就意味着Feign Client有多个相同的Bean在Spring容器中,当我们在使用@Autowired进行注入的时候,不知道注入哪个,所以我们需要设置一个优先级高的,@Primary注解就是干这件事情的。 | |
qualifier | 介绍如下 |
7.1 contextId
比如我们有个user服务,但user服务中有很多个接口,我们不想将所有的调用接口都定义在一个类中,比如:
Client 1
Client 2
这种情况下启动就会报错了,因为Bean的名称冲突了,具体错误如下:
解决方案可以增加下面的配置,作用是允许出现beanName一样的BeanDefinition。
另一种解决方案就是为每个Client手动指定不同的contextId,这样就不会冲突了。
上面给出了Bean名称冲突后的解决方案,下面来分析下contextId在Feign Client的作用,在注册Feign Client Configuration的时候需要一个名称,名称是通过getClientName方法获取的:
可以看到如果配置了contextId就会用contextId,如果没有配置就会去value然后是name最后是serviceId。默认都没有配置,当出现一个服务有多个Feign Client的时候就会报错了。
其次的作用是在注册FeignClient中,contextId会作为Client 别名的一部分,如果配置了qualifier优先用qualifier作为别名。
7.2 qualifier
qualifier对应的是@Qualifier注解,使用场景跟上面的primary关系很淡,一般场景直接@Autowired直接注入就可以了。
如果我们的Feign Client有fallback实现,默认@FeignClient注解的primary=true, 意味着我们使用@Autowired注入是没有问题的,会优先注入你的Feign Client。
如果你鬼斧神差的把primary设置成false了,直接用@Autowired注入的地方就会报错,不知道要注入哪个对象。
解决方案很明显,你可以将primary设置成true即可,如果由于某些特殊原因,你必须得去掉primary=true的设置,这种情况下我们怎么进行注入,我们可以配置一个qualifier,然后使用@Qualifier注解进行注入,示列如下:
Feign Client定义
Feign Client注入
__EOF__
本文链接:https://www.cnblogs.com/ludangxin/p/16051873.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!