iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >如何自定义feign调用实现hystrix超时、异常熔断
  • 576
分享到

如何自定义feign调用实现hystrix超时、异常熔断

2024-04-02 19:04:59 576人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

需求描述 spring cloud 项目中feign 整合 hystrix经常使用,但是最近发现hystrix功能强大,但是对我们来说有些大材小用。 首先我只需要他的一个熔断作用,就

需求描述

spring cloud 项目中feign 整合 hystrix经常使用,但是最近发现hystrix功能强大,但是对我们来说有些大材小用。

首先我只需要他的一个熔断作用,就是说请求超时、异常了返回 FeignClient注解中配置的fallback,不需要非阻塞操作、也不需要重试,hystrix 调用feign时候做了线程池隔离处理,这样增加了项目复杂度(线程池参数配置、线程少了请求服务直接拒绝,多了线程得管理。。。)

目前feign 超时之后是直接抛异常的,这样的话虽然是及时熔断了,但是正常的程序逻辑不走了配置的fallback也没有作用,这个配置项得配合 hystrix 才行。

我需要的是这样的效果


  try{
     feign.api();
  }catch(){
  return fallback();
 }

但是每个feign调用都手动加上try..catch 实在是太low了,最好能写个类似切面一样的玩意。

这时候就想到了 hystrix,既然人家框架已经做了,我直接看下代码,copy不完了么

源码学习

前两天发布了一篇文章也是关于feign、hystrix 调用集成的

基于之前的分析关键代码


HystrixInvocationHandler (feign.hystrix)

@Override
  public Object invoke(final Object proxy, final Method method, final Object[] args)
      throws Throwable {
    .............
  // setterMethodMap 封装 hystrixCommand 配置信息(超时时间、是否重试.....)
    HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
      @Override
      protected Object run() throws Exception {
        ....
        HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
       ....
      }
      @Override
      protected Object getFallback() {
        .........
      }
    };
   ......
    return hystrixCommand.execute();
  }

按照之前分析源码方式,直接看哪里被调用了就可以看到, hystrix 实际上自己封装了一个 feign.Builer 类名是 feign.hystrix.HystrixFeign.Builder 用的是建造者模式,生成的类是在调用服务时用到

看到 关键的 build() 方法


Feign build(final FallbackFactory<?> nullableFallbackFactory) {
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        // 重新定义一个 InvocationHandler 实现 类似 aop效果
        @Override public InvocationHandler create(Target target,
            Map<Method, MethodHandler> dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
        }
      });
      super.contract(new HystrixDelegatinGContract(contract));
      return super.build();
    }

spring 动态代理我这里不多说了,核心就是 InvocationHandler (如果是jdk动态代理的话),那么 feign 这里也是,我们看看feign 调用声明是个接口,实际上是spring 动态代理生成了代理类,调用方法时实际调用的是


java.lang.reflect.InvocationHandler#invoke

方案构想

那么我们只需要借鉴下 hystrix 的方式,自己实现一个feign.build ,将 InvocationHandler 换成自己的,

然后在我们自己的 InvocationHandler 中调用feign 官方的 InvocationHandler 就行,也就是


feign.hystrix.HystrixInvocationHandler#invoke

这个方法中的


this.dispatch.get(method).invoke(args);

这个代码

方案具体代码实现

方案一

自己实现


import feign.Feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;

public class CusFeignBuilder extends Feign.Builder{
    public CusFeignBuilder() {
        this.invocationHandlerFactory((target, dispatch) -> {
            Class<?> type = target.type();
            FeignClient annotation = type.getAnnotation(FeignClient.class);
            // 构造 fallback 实例
            Object fallBackObj = null;
            if (annotation != null && !annotation.fallback().equals(void.class)) {
                try {
                    fallBackObj = annotation.fallback().newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            return new CusFeignInvocationHandler(target, dispatch, fallBackObj);
        });
    }
}

import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FeignClient;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.eco.common.utils.Md5Util.logger;
import static feign.Util.checkNotNull;

@Slf4j
public class CusFeignInvocationHandler implements InvocationHandler {
    private final Target target;
    private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
    private final Object fallbackObj;
    private final Map<String, Method> fallbackMethodMap = new ConcurrentHashMap<>();
    CusFeignInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, Object  fallbackObj) {
        this.target = checkNotNull(target, "target");
        this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
        this.fallbackObj = fallbackObj;
    }
    public Object feignInvoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("equals".equals(method.getName())) {
            try {
                Object
                        otherHandler =
                        args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return equals(otherHandler);
            } catch (IllegalArgumentException e) {
                return false;
            }
        } else if ("hashCode".equals(method.getName())) {
            return hashCode();
        } else if ("toString".equals(method.getName())) {
            return toString();
        }
        return dispatch.get(method).invoke(args);
    }
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof CusFeignInvocationHandler) {
            CusFeignInvocationHandler other = (CusFeignInvocationHandler) obj;
            return target.equals(other.target);
        }
        return false;
    }
    @Override
    public int hashCode() {
        return target.hashCode();
    }
    @Override
    public String toString() {
        return target.toString();
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            return feignInvoke(proxy, method, args);
        } catch (Throwable throwable) {
            String configKey = Feign.configKey(target.type(), method);
            logger.error("{} 请求 出现异常 ==> {}", configKey, throwable.getMessage());
            try {
                return getFallbackReturn(method, args, throwable);
            } catch (Throwable e) {
                throw throwable;
            }
        }
    }
    
    public Object getFallbackReturn(Method method, Object[] args, Throwable throwable) throws Throwable {
        if (fallbackObj == null) {
            throw new RuntimeException("fallbackObj is null");
        }
        String configKey = Feign.configKey(target.type(), method);
        Method fallbackMethod = fallbackMethodMap.get(configKey);
        if (fallbackMethod == null) {
            Class<?> declaringClass = method.getDeclaringClass();
            FeignClient annotation = declaringClass.getAnnotation(FeignClient.class);
            if (annotation == null) {
                throw new RuntimeException("FeignClient annotation not found");
            }
            // 失败返回
            Class<?> fallback = annotation.fallback();
            fallbackMethod = fallback.getMethod(method.getName(), method.getParameterTypes());
            fallbackMethodMap.put(configKey, fallbackMethod);
        }
        if (fallbackMethod == null) {
            throw new RuntimeException("fallbackMethodMap not found");
        }
        return fallbackMethod.invoke(fallbackObj, args);
    }
}

然后在 spring 容器中注册这个bean就行


@Bean
    CusFeignBuilder cusFeignBuilder(){
        return new CusFeignBuilder();
    }

方案二

集成 sentinel ,今天写博客再回头看源码时候才发现的

加入依赖


<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置开启


feign.sentinel.enabled=true

手动实现feign 接口,将实体类注册到 spring 中


@Component
public class DeviceApiFallBack implements DeviceApi{
  @Override
        public ServerResponse<String> login(String appId) {
            return ServerResponse.createByErrORMessage("请求失败");
        }
}

其实看代码知道原理一样,无非实现方式不一样

两个方案其实都行,方案一自己实现代码量多,方案二sentinel 官方实现,但是需要引入依赖,增加复杂度,而且 接口实现需要注册到spring 中

目前我选的还是方案一,简单。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 如何自定义feign调用实现hystrix超时、异常熔断

本文链接: https://www.lsjlt.com/news/129057.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何自定义feign调用实现hystrix超时、异常熔断
    需求描述 spring cloud 项目中feign 整合 hystrix经常使用,但是最近发现hystrix功能强大,但是对我们来说有些大材小用。 首先我只需要他的一个熔断作用,就...
    99+
    2024-04-02
  • SpringCloud怎么实现服务调用feign、熔断hystrix和网关gateway
    本文小编为大家详细介绍“SpringCloud怎么实现服务调用feign、熔断hystrix和网关gateway”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringCloud怎么实现服务调用feign、熔断hystrix和网关gat...
    99+
    2023-07-05
  • SpringCloud实现服务调用feign与熔断hystrix和网关gateway详细分析
    回归cloud的学习,对于springcloud的架构与原理以及性能的分析我们都在之前的文章里写过: springcloud架构的认识 我们之前测试过eureka服务注册功能,它能很...
    99+
    2023-05-14
    SpringCloud服务调用feign SpringCloud熔断hystrix SpringCloud网关gateway
  • 使用Java如何实现异常自定义
    今天就跟大家聊聊有关使用Java如何实现异常自定义,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。具体代码如下所示: class ChushulingException ext...
    99+
    2023-05-31
    java 自定义异常 ava
  • springboot如何实现全局异常处理及自定义异常类
    这篇文章主要介绍springboot如何实现全局异常处理及自定义异常类,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!全局异常处理及自定义异常类全局异常处理定义一个处理类,使用@ControllerAdvice注解。@...
    99+
    2023-06-29
  • Springboot项目中如何实现异常处理自定义
    这期内容当中小编将会给大家带来有关Springboot项目中如何实现异常处理自定义,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。背景Springboot 默认把异常的处理集中到一个ModelAndView...
    99+
    2023-05-31
    springboot 异常处理 目中
  • python中如何使用自定义异常类
    本篇文章为大家展示了python中如何使用自定义异常类,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。自定义异常类自定义类继承系统的异常基类exception自定义异常类的构造函数等方法进行处理举例:...
    99+
    2023-06-20
  • 如何用C#创建用户自定义异常浅析
    概述 异常是在程序执行期间出现的问题。C# 中的异常是对程序运行时出现的特殊情况的一种响应,比如尝试除以零。异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。C# 异常处...
    99+
    2024-04-02
  • 如何使用python写一段自定义异常代码
    这篇文章主要为大家展示了“如何使用python写一段自定义异常代码”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用python写一段自定义异常代码”这篇文...
    99+
    2024-04-02
  • 如何在Vue3中实现自定义指令(超详细!)
    目录前言生命周期钩子的参数简化形式对象字面量在组件上使用指令几个实用的自定义指令自动聚焦v-focus防抖v-debounce节流v-throttle弹窗隐藏v-hide总结在开发V...
    99+
    2024-04-02
  • win10系统如何实现窗口自定义调整
    这篇文章主要为大家展示了“win10系统如何实现窗口自定义调整”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“win10系统如何实现窗口自定义调整”这篇文章吧。按win+r打开运行窗口,输入reg...
    99+
    2023-06-28
  • java如何实现自定义时钟并走时功能
    本文小编为大家详细介绍“java如何实现自定义时钟并走时功能”,内容详细,步骤清晰,细节处理妥当,希望这篇“java如何实现自定义时钟并走时功能”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。效果图:很多人想要自己...
    99+
    2023-07-02
  • android自定义控件如何实现简易时间轴
    这篇“android自定义控件如何实现简易时间轴”除了程序员外大部分人都不太理解,今天小编为了让大家更加理解“android自定义控件如何实现简易时间轴”,给大家总结了以下内容,具有一定借鉴价值,内容详细步骤清晰,细节处理妥当,希望大家通过...
    99+
    2023-06-28
  • 如何测试和调试自定义的golang函数实现
    单元测试自定义函数涉及创建测试文件、定义测试函数、编写测试用例和执行断言。调试失败的测试涉及启用调试信息、使用调试器和设置断点。 如何测试和调试自定义 Go 函数实现 在 Go 中,测...
    99+
    2024-04-26
    调试 golang
  • Android如何实现一个倒计时自定义控件
    这篇“Android如何实现一个倒计时自定义控件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android如何实现一个倒计...
    99+
    2023-06-29
  • Timer如何实现自定义时间间隔的连环炸
    这篇文章主要介绍“Timer如何实现自定义时间间隔的连环炸”,在日常操作中,相信很多人在Timer如何实现自定义时间间隔的连环炸问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Timer如何实现自定义时间间隔的...
    99+
    2023-06-02
  • 使用Spring AOP 如何实现自定义注解
    这期内容当中小编将会给大家带来有关使用Spring AOP 如何实现自定义注解,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在Maven中加入以下以依赖:<!-- Spring AOP + Aspe...
    99+
    2023-05-31
    springaop 注解
  • Android如何实现自定义可复用的BaseAdapter
    这篇文章主要讲解了“Android如何实现自定义可复用的BaseAdapter”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android如何实现自定义可复用的BaseAdapter”吧!项...
    99+
    2023-07-04
  • 如何在Android应用中实现自定义View
    本篇文章为大家展示了如何在Android应用中实现自定义View,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Android自定义view的种类自定义view大概可以分为四个大类,主要是通过实现方式...
    99+
    2023-05-31
    android view roi
  • springboot为异步任务规划自定义线程池如何实现
    本篇内容主要讲解“springboot为异步任务规划自定义线程池如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot为异步任务规划自定义线程池如何实现”吧!一、Spring...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作