SpringCloud Alibaba微服务实战二十

Easter79
• 阅读 480

SpringCloud Alibaba微服务实战二十

在之前的项目中我们已经实现了使用Feign调用远程接口,本章内容主要是借助sentinel实现Feign接口熔断器功能。

概述

首先我们看看不使用熔断器的情况下调用一个没有启动的服务会出现什么效果,然后再来看看使用sentinel熔断器后的效果。

SpringCloud Alibaba微服务实战二十

如上,我们使用order-service中 FeignController调用account-service中的接口,在没启用熔断器的情况下,接口会抛出500异常。

实现

使用sentinel实现熔断器很简单,简单几步即可。

  1. 定义fallback类,当熔断时返回默认数据

    package com.javadaily.feign.fallback;@Slf4jpublic class AccountFeignFallback implements AccountFeign {    @Setter    private Throwable cause;    @Override    public ResultData insert(AccountDTO accountDTO) {        return ResultData.fail("接口熔断");    }    @Override    public ResultData delete(String accountCode) {        return ResultData.fail("接口熔断");    }    @Override    public ResultData update(AccountDTO accountDTO) {        return ResultData.fail("接口熔断");    }    @Override    public ResultData getByCode(String accountCode) {        log.error("查询失败,接口异常" ,cause);        AccountDTO account = new AccountDTO();        account.setAccountCode("000");        account.setAccountName("测试Feign");        return ResultData.success(account);    }    @Override    public ResultData reduce(String accountCode, BigDecimal amount) {        return ResultData.fail("接口熔断");    }}

  2. 编写FallbackFactory

    @Componentpublic class AccountFeignFallbackFactory implements FallbackFactory {    @Override    public AccountFeign create(Throwable throwable) {        AccountFeignFallback accountFeignFallback = new AccountFeignFallback();        accountFeignFallback.setCause(throwable);        return accountFeignFallback;    }}

  3. 给feign接口指定熔断工厂

    @FeignClient(name = "account-service",fallbackFactory = AccountFeignFallbackFactory.class)public interface AccountFeign {    ...}

  4. 在消费中配置文件中开启熔断

    feign:  sentinel:    enabled: true

经过以上四步我们就可以实现了接口的熔断,接下来重新启动order-service验证结果。系统居然无法正常启动!!!

SpringCloud Alibaba微服务实战二十

堆栈信息如下:

2020-10-23 15:22:14,286 ERROR SpringApplication:826 - Application run failedorg.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)@Documentedpublic @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"})

至此所有问题都解决,我们再次访问接口,当系统故障时返回我们默认结果。

SpringCloud Alibaba微服务实战二十

小结

本章内容我们通过给Feign的接口加上熔断器,当实例故障时系统会返回默认数据。这样就不会出现当某一个服务不可用时导致他的消费者长时间等待,线程池耗尽,进而影响到其他服务的线程调用,这也是常说的 "雪崩效应"。

当然了实现过程中出现了一点小挫折,总结下来就是「如果各位的Feign客户端是由消费者自己编写,位于消费者自己模块不会出现这个问题。如果是由生产者编写并提供则需要注意Spring Bean实例化的扫描路径,如果无法扫描实例化熔断类,只需要在启动类上通过 scanBasePackages扫描到对应的路径即可」

如果本文对你有帮助,

别忘记来个三连:

点赞,转发,评论

咱们下期见!

收藏 等于白嫖点赞 才是真情!

End

干货分享

这里为大家准备了一份小小的礼物,关注公众号,输入如下代码,即可获得百度网盘地址,无套路领取!

001:《程序员必读书籍》
002:《从无到有搭建中小型互联网公司后台服务架构与运维架构》
003:《互联网企业高并发解决方案》
004:《互联网架构教学视频》
006:《SpringBoot实现点餐系统》
007:《SpringSecurity实战视频》
008:《Hadoop实战教学视频》
009:《腾讯2019Techo开发者大会PPT》

010: 微信交流群

近期热文top

1、关于JWT Token 自动续期的解决方案

2、SpringBoot开发秘籍-事件异步处理

3、架构师之路-服务器硬件扫盲

4、架构师之路-微服务技术选型

5、RocketMQ进阶 - 事务消息

SpringCloud Alibaba微服务实战二十

我就知道你“在看”

SpringCloud Alibaba微服务实战二十

本文分享自微信公众号 - JAVA日知录(javadaily)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Feign请求响应结果被截取com.fasterxml.jackson.core.io.JsonEOFException
在生产环境使用feign调用外部接口时,偶尔会出现下面错误2020101511:00:18,535ERRORcom.shein.abc.rmp.controller.RecExplainConfigControllerrec_explain_query.failffeign.codec.DecodeExc
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k