

Spring Cloud Alibaba 微服务实战(二十) :集成 Feign 的降级熔断
source link: https://mp.weixin.qq.com/s/GSrPCLB-lG8m8uQOwzQwCw
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在之前的项目中我们已经实现了使用Feign调用远程接口,本章内容主要是借助sentinel实现Feign接口熔断器功能。
首先我们看看不使用熔断器的情况下调用一个没有启动的服务会出现什么效果,然后再来看看使用sentinel熔断器后的效果。

如上,我们使用order-service中 FeignController
调用account-service中的接口,在没启用熔断器的情况下,接口会抛出500异常。
使用sentinel实现熔断器很简单,简单几步即可。
-
定义fallback类,当熔断时返回默认数据
package com.javadaily.feign.fallback; @Slf4j public class AccountFeignFallback implements AccountFeign { @Setter private Throwable cause; @Override public ResultData<String> insert(AccountDTO accountDTO) { return ResultData.fail("接口熔断"); } @Override public ResultData<String> delete(String accountCode) { return ResultData.fail("接口熔断"); } @Override public ResultData<String> update(AccountDTO accountDTO) { return ResultData.fail("接口熔断"); } @Override public ResultData<AccountDTO> getByCode(String accountCode) { log.error("查询失败,接口异常" ,cause); AccountDTO account = new AccountDTO(); account.setAccountCode("000"); account.setAccountName("测试Feign"); return ResultData.success(account); } @Override public ResultData<String> reduce(String accountCode, BigDecimal amount) { return ResultData.fail("接口熔断"); } }
-
编写FallbackFactory
@Component public class AccountFeignFallbackFactory implements FallbackFactory<AccountFeign> { @Override public AccountFeign create(Throwable throwable) { AccountFeignFallback accountFeignFallback = new AccountFeignFallback(); accountFeignFallback.setCause(throwable); return accountFeignFallback; } }
-
给feign接口指定熔断工厂
@FeignClient(name = "account-service",fallbackFactory = AccountFeignFallbackFactory.class) public interface AccountFeign { ... }
-
在消费中配置文件中开启熔断
feign: sentinel: enabled: true
经过以上四步我们就可以实现了接口的熔断,接下来重新启动order-service验证结果。系统居然无法正常启动!!!

堆栈信息如下:
2020-10-23 15:22:14,286 ERROR SpringApplication:826 - Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'feignController': Unsatisfied dependency expressed through field 'accountFeign'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.javadaily.feign.account.AccountFeign': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: No fallbackFactory instance of type class com.javadaily.feign.factory.AccountFeignFallbackFactory found for feign client account-service at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
问题解决
俗话说 「出现问题不可怕,可怕的是我们害怕出现问题」 ,看上面的启动日志应该是无法找到 AccountFeignFallbackFactory
,接下来我们看一下FeignClient的源码:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface FeignClient { ...省略部分代码,保留关键代码... /** * Fallback class for the specified Feign client interface. The fallback class must * implement the interface annotated by this annotation and be a valid spring bean. * @return fallback class for the specified Feign client interface */ Class<?> fallback() default void.class; ...省略部分代码,保留关键代码... }
注意看注释部分,说的是Feign的降级类必须实现该Feign接口并且必须是一个Spring Bean。
出现错误的原因应该是 「降级类没有被注册成Spring Bean。」
大家都知道,在SpringBoot启动的时候会默认扫描主启动类所在的包以及子包进行Bean实例化。
项目中的order-service的主启动类位于 com.javadaily.order
,那么order-service项目启动时只会扫描到 com.javadaily.order
以及 com.javadaily.order
的子包,而AccountFeignClient的降级类 AccountFeignFallback
的包路径为 com.javadaily.feign.fallback
,这样就无法被Spring实例化,最终导致项目启动失败。
既然定位到了问题原因那就很好解决了,只要在启动类上配置Feign降级类的包路径即可。
@SpringBootApplication(scanBasePackages = {"com.javadaily.feign"})
加上这个配置后系统能正常启动,但是调用接口又返回如下的错误:
{ "timestamp": "2020-10-27T03:30:44.664+0000", "status": 401, "error": "Unauthorized", "message": "Unauthorized", "path": "/order/getAccount/jianzh5" }
出现这个问题的原因是我们通过scanBasePackages配置Feign降级类的路径后自身的Bean无法实例化,所以我们还需要配置上我们自己项目的扫描路径,即:
@SpringBootApplication(scanBasePackages = {"com.javadaily.feign","com.javadaily.order"})
至此所有问题都解决,我们再次访问接口,当系统故障时返回我们默认结果。

本章内容我们通过给Feign的接口加上熔断器,当实例故障时系统会返回默认数据。这样就不会出现当某一个服务不可用时导致他的消费者长时间等待,线程池耗尽,进而影响到其他服务的线程调用,这也是常说的 "雪崩效应"。
当然了实现过程中出现了一点小挫折,总结下来就是 「如果各位的Feign客户端是由消费者自己编写,位于消费者自己模块不会出现这个问题。如果是由生产者编写并提供则需要注意Spring Bean实例化的扫描路径,如果无法扫描实例化熔断类,只需要在启动类上通过 scanBasePackages
扫描到对应的路径即可」 。
如果本文对你有帮助,
别忘记来个三连:
点赞,转发,评论
。
咱们下期见!
收藏 等于白嫖 , 点赞 才是真情!
End
干货分享
这里为大家准备了一份小小的礼物,关注公众号,输入如下代码,即可获得百度网盘地址,无套路领取!
001:《程序员必读书籍》
002:《从无到有搭建中小型互联网公司后台服务架构与运维架构》
003:《互联网企业高并发解决方案》
004:《互联网架构教学视频》
006:《SpringBoot实现点餐系统》
007:《SpringSecurity实战视频》
008:《Hadoop实战教学视频》
009:《腾讯2019Techo开发者大会PPT》
010: 微信交流群
近期热文top
我就知道你“在看”
Recommend
-
53
上篇介绍了 Spring Boot 集成 Dubbo,使我们的系统打下了分布式的基础。随着程序功能的日益复杂,程序的配置日益增多:各种功能开关、参数配置、服务器地址等;对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集...
-
14
SpringCloud Alibaba微服务实战二十三 - Feign 性能调优 ...
-
11
SpringCloud Alibaba微服务实战二十七 使用SpringCloud架构后我们希望所有的请求...
-
17
使用SpringCloud架构后我们希望所有的请求都需要经过网关才能访问,在不作任何处理的情况下我们是可以绕过网关直接访问后端服务的。如下,...
-
6
前面文章咱们对比过网关授权与微服务授权的区别,文章也提到了,如果要实现微服务授权,一般会构建一个独立的资源服务器配置模块,否则每个后端业务都需要进行资源服务器的配置,那本节内容我们就来完成此功能。 由于间隔时间...
-
5
SpringCloud Alibaba微服务实战三十二 大家好,我是飘渺Jam,一名来自三流城市三流公司的三流程序员,这是我们的第159篇原创文章,如果你喜欢请记得给我一个点赞与转发。 这篇文章来源于粉丝...
-
17
download:Spring Cloud / Alibaba 微服务架构实战为提高搜索的精确度,推荐使用配套工具截图
-
6
SpringCloud-Alibaba致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud编程模型轻松使用这些组件来开发分布式应用服务。 依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 S...
-
1
Spring Boot 3.0 (二十):Spring Boot 集成 Memcached 2023/01/20...
-
2
本文给大家介绍一下在 Spring Boot 项目中如何集成消息队列 RabbitMQ,包含对 RibbitMQ 的架构介绍、应用场景、坑点解析以及代码实战。最后文末有免费领取龙年红包封面以及腾讯云社区答题领奖福利,欢迎大家领取。我将使用 waynboot-mall 项目作为代码讲解,...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK