简单谈谈Feign

article/2025/9/2 10:03:16

简单谈谈Feign

文章目录

  • 简单谈谈Feign
    • 前言
      • Feign属于RPC嘛?
    • 原理简单图解
    • 原理简述
      • Feign.Build
      • 动态代理工厂InvocationHandlerFactory
        • 动态代理类FeignInvocationHandler
          • 方法处理器MethodHandler
    • 总结

本文只是简单粗略的分析一下feign的源码与过程原理

前言

FeignNetflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API

Spring CloudFeign进行了增强,整合了Spring Cloud RibbonSpring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。

Feign属于RPC嘛?

市面上的基于RPC的开源框架更多的是指基于TCP(或其他协议)、自带服务治理等等等等

由此可见,feign也许并不完全属于RPC的概念,可是今天看到一个博主写的一句话我觉得说的很对

其实判断RPC尽可以不那么复杂,你像调本地接口一样调用远程接口的方式,那它就是RPC

RPC的初衷就是让开发者在实现对其他服务的远程调用时,可以尽可能地减少对于网络通信等层面的关心,而专注于业务上的实现,所以其实不管它是基于HTTP还是基于TCP还是基于啥啥啥的,既然它为我们简化了使用,那我就认为它是一款合格的“RPC框架”

原理简单图解

原理简述

Feign.Build

public abstract class Feign类下有一个继承了BaseaBuilder类的类public static class Builder extends BaseBuilder<Builder>

在老版本的feign中好像是没有这个BaseBuilder的,而是将一些成员变量直接放在Builder

在新版Feign中才将这些成员变量放到了BaseBuilder中,然后用Builder去继承BaseBuilder

public abstract class BaseBuilder<B extends BaseBuilder<B>> {// 请求拦截器protected final List<RequestInterceptor> requestInterceptors = new ArrayList<>();// 响应拦截器protected ResponseInterceptor responseInterceptor = ResponseInterceptor.DEFAULT;// 日志记录级别protected Logger.Level logLevel = Logger.Level.NONE;// 规则解析器protected Contract contract = new Contract.Default();// 重试机制器protected Retryer retryer = new Retryer.Default();// 日志protected Logger logger = new NoOpLogger();// 编码器protected Encoder encoder = new Encoder.Default();// 解码器protected Decoder decoder = new Decoder.Default();protected boolean closeAfterDecode = true;protected QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();protected ErrorDecoder errorDecoder = new ErrorDecoder.Default();protected Options options = new Options();// 动态代理工厂类protected InvocationHandlerFactory invocationHandlerFactory =new InvocationHandlerFactory.Default();protected boolean dismiss404;protected ExceptionPropagationPolicy propagationPolicy = NONE;protected List<Capability> capabilities = new ArrayList<>();
}

动态代理工厂InvocationHandlerFactory

Feign的组件中,所有的动态代理类对象都是通过InvocationHandlerFactory工厂完成的

InvocationHandlerFactory类中有一个实现了InvocationHandlerFactory接口并重写了create方法的实现类,用于创建动态代理处理器对象

这里不仅仅只有一个用于构建FeignInvocationHandler代理的默认类

也可以由HystrixFeign、SentinelFeign去实现这个create方法

在微服务启动时,Feign会进行包扫描,对加@FeignClient注解的接口,按照注解的规则,创建远程接口的本地JDK Proxy代理实例。

然后,将这些本地Proxy代理实例,注入到Spring IOC容器中。当远程接口的方法被调用,由Proxy代理实例去完成真正的远程访问,并且返回结果

public interface InvocationHandlerFactory {InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);interface MethodHandler {Object invoke(Object[] argv) throws Throwable;}static final class Default implements InvocationHandlerFactory {@Overridepublic InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);}}
}

动态代理类FeignInvocationHandler

我们平时在使用JDK的动态代理时都是

  • 新建一个处理类并实现InvocationHandler接口
  • 实现invoke方法,作为被代理接口的方法代理实现

feign也不例外,它有一个ReflectiveFeign类,其中有着一个实现了InvocationHandler接口并实现了invoke方法的静态类FeignInvocationHandler

而这个FeignInvocationHandler就是被动态代理工厂类InvocationHandlerFactory去创建的(见上文代码)

我们应该也注意到了这个成员变量Map<Method, MethodHandler> dispatch

它维护了一个method对应MethodHandler的mapMethodHandlerInvocationHandlerFactory的一个接口,里面包含了一个invoke方法,那么其作用也很明显了

在处理远程方法调用的时候,执行FeignInvocationHandler的invoke方法

然后通过Java反射的方法作为key,在dispatch 映射对象中,找到对应的MethodHandler 方法处理器,然后交给MethodHandler的invoke方法来完成实际的HTTP请求和结果的处理

public class ReflectiveFeign extends Feign {  static class FeignInvocationHandler implements InvocationHandler {private final Target target;private final Map<Method, MethodHandler> dispatch;FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {this.target = checkNotNull(target, "target");this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);}@Overridepublic Object invoke(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);}}
}
方法处理器MethodHandler

InvocationHandlerFactory接口中的一个很简单的接口,只有一个invoke方法

主要职责是完成实际远程URL请求,然后返回解码后的远程URL的响应结果

  interface MethodHandler {Object invoke(Object[] argv) throws Throwable;}

其有两个实现类DefaultMethodHandler(这个暂时忽略)与SynchronousMethodHandler

SynchronousMethodHandler实现类提供了基本的远程URL的同步请求处理

我们这里来说一下SynchronousMethodHandler类是如何去处理远程请求与结果响应的

  • 构建请求模板RequestTemplate与请求参数
  • 通过请求模板构建请求
    • 拦截器构建请求,例如构建请求头相关参数
  • 通过Client接口的实现类发送请求并获取结果响应
    • 值得一提的是,Client接口有很多实现类,例如其本身default类、LoadBalancerFeignClient
  • AsyncResponseHandler类去处理响应结果并返回最终结果
    • 其中就调用了ResponseInterceptorfeign自带的Decoder去将响应进行解码操作
final class SynchronousMethodHandler implements MethodHandler {// 执行Handler 的处理@Overridepublic Object invoke(Object[] argv) throws Throwable {// 构建请求模板RequestTemplateRequestTemplate template = buildTemplateFromArgs.create(argv);// 构建请求参数Options options = findOptions(argv);// 获取重试机制器Retryer retryer = this.retryer.clone();while (true) {try {// 执行请求并解码return executeAndDecode(template, options);} catch (RetryableException e) {try {retryer.continueOrPropagate(e);} catch (RetryableException th) {Throwable cause = th.getCause();if (propagationPolicy == UNWRAP && cause != null) {throw cause;} else {throw th;}}if (logLevel != Logger.Level.NONE) {logger.logRetry(metadata.configKey(), logLevel);}continue;}}}// 执行请求,然后解码结果Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {// 构建请求Request request = targetRequest(template);Response response;long start = System.nanoTime();try {// 执行请求,并获取结果response = client.execute(request, options);response = response.toBuilder().request(request).requestTemplate(template).build();} catch (IOException e) {if (logLevel != Logger.Level.NONE) {logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));}throw errorExecuting(request, e);}long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);if (decoder != null) {return responseInterceptor.aroundDecode(new InvocationContext(decoder, metadata.returnType(), response));}CompletableFuture<Object> resultFuture = new CompletableFuture<>();asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,metadata.returnType(), elapsedTime);try {if (!resultFuture.isDone())throw new IllegalStateException("Response handling not done");return resultFuture.join();} catch (CompletionException e) {Throwable cause = e.getCause();if (cause != null)throw cause;throw e;}}// Request targetRequest(RequestTemplate template) {// 拦截器构建请求,例如构建请求头相关参数for (RequestInterceptor interceptor : requestInterceptors) {interceptor.apply(template);}// 返回构建好的请求return target.apply(template);}
}

总结

具体的代码就不贴了,源码里都有,最后再简单总结一下Feign的调用流程

  • 初始化阶段
    • 装配代理实例:为@FeignClient注解的所有远程接口通过InvocationHandlerFactory构建FeignInvocationHandler的处理器实例到IOC容器
      • 如果是hystrixsentinel,则构造其对应的处理器实例
      • 构建时,维护了一个Map<Method, MethodHandler> dispatch
  • 调用阶段
    • 依赖注入feign接口
    • InvokeHandler.invoke:调用相关方法时,实际上是通过FeignInvocationHandler处理器实例执行invoke方法
      • MethodHandler.invoke:根据方法名称从dispatch中拿到MethodHandler的实现子类执行其invoke方法(例如SynchronousMethodHandler
      • 构建请求模板RequestTemplate与请求参数options
        • 拦截器构建请求,例如构建请求头相关参数
        • 返回构建好的请求
      • feign.Client完成远程 URL 请求执行和获取远程结果
        • Client接口的实现类发送请求并获取结果响应
        • Client实现类将获取的响应结果解码并返回

最后,默认的与 FeignInvocationHandler 相关的远程调用执行流程,在运行机制以及调用性能上,满足不了生产环境的要求

  • 没有远程调用过程中的熔断监测和恢复机制;
  • 也没有用到高性能的HTTP连接池技术

所以应该使用Hystrix相关的HystrixInvocationHandler去进行更高性能、高可用的处理远程调用


http://chatgpt.dhexx.cn/article/qXuIGxOp.shtml

相关文章

Feign 原理 (图解)

疯狂创客圈 经典图书 &#xff1a; 《Netty Zookeeper Redis 高并发实战》 面试必备 面试必备 面试必备 【博客园总入口 】 疯狂创客圈 经典图书 &#xff1a; 《SpringCloud、Nginx高并发核心编程》 大厂必备 大厂必备 大厂必备 【博客园总入口 】 入大厂涨工资 必备的 …

Feign详解与实例

基本介绍 Feign是一种负载均衡的HTTP客户端, 使用Feign调用API就像调用本地方法一样&#xff0c;从避免了调用目标微服务时&#xff0c;需要不断的解析/封装json 数据的繁琐。Feign集成了Ribbon。Ribboneureka是面向微服务编程&#xff0c;而Feign是面向接口编程。 Fegin是一个…

Feign使用和原理的总结

官方参考 https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/ 使用 引入依赖 <properties><java.version>1.8</java.version><spring-cloud.version>2021.0.1</spring-cloud.version></properties><depen…

Feign的介绍

Feign是springcloud里面的一个功能组件&#xff0c;那么它是实现一个什么功能呢&#xff1f; 首先我们可以先从字面意思上去理解一下它&#xff0c;Feign&#xff0c;英文翻译过来就是伪装的意思&#xff0c;实际上它的功能也是和伪装相关的&#xff0c;在我们之前在客户端配置…

FeignClient原理解读

FeignClient原理解读 简介源码解读feign负载ribbon源码解读eurake的ribbon原理是&#xff1a;调度原理&#xff1a; 笔记参考文献 简介 这一章节主要介绍feignClient的地址如何来&#xff0c;如何从feign Server注册中心寻址和调用。 源码解读 在解读源码之前&#xff0c;建…

Spring Cloud-Feign设计原理

什么是Feign&#xff1f; Feign 的英文表意为“假装&#xff0c;伪装&#xff0c;变形”&#xff0c; 是一个http请求调用的轻量级框架&#xff0c;可以以Java接口注解的方式调用Http请求&#xff0c;而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解&am…

再学一下Feign的原理

简介 Feign是Spring Cloud Netflix组件中的一个轻量级Restful的HTTP服务客户端&#xff0c;它简化了服务间调用的方式。 Feign是一个声明式的web service客户端.它的出现使开发web service客户端变得更简单.使用Feign只需要创建一个接口加上对应的注解, 比如FeignClient注解。…

Feign的底层原理

Feign的底层原理 1 EnableFeignClients2 根据接口上的注解创建RequestTemplate3 发送请求 1 EnableFeignClients 这个注解标注在springboot的启动类上,作用是开启feign接口扫描 FeignClientsRegistrar.registerFeignClients()扫描被FeignClient标识的接口生成代理类 public vo…

深入理解Feign之源码解析

转载请标明出处&#xff1a; https://blog.csdn.net/forezp/article/details/73480304 本文出自方志朋的博客 出自方志朋的博客 个人博客纯净版&#xff1a;https://www.fangzhipeng.com/springcloud/2017/08/11/sc-feign-raw.html 什么是Feign Feign是受到Retrofit&#xff…

SpringCloud 中Feign原理(图解)

1 SpringCloud 中Feign原理 1.1 Feign简介 Feign是Netflix公司开源的轻量级rest客户端&#xff0c;使用Feign可以非常方便的实现Http 客户端。Spring Cloud引入Feign并且集成了Ribbon实现客户端负载均衡调用。 1.2 Feign远程调用的基本流程 Feign远程调用&#xff0c;核心就是…

Feign(简介和使用)

1. Feign介绍 通过RestTemplate调用其它服务的API时&#xff0c;所需要的参数须在请求的URL中进行拼接&#xff0c;如果参数少的话或许我们还可以忍受&#xff0c;一旦有多个参数的话&#xff0c;这时拼接请求字符串就会效率低下 Feign是一个声明式的Web Service客户端&#…

什么是Feign?

服务间调用介绍 现有的服务调用方式 利用拼接的方式。 虽然上面有的用不错就很好了 Feign解决了什么问题 Feign的调用方式 Feign体系架构解析-武装到牙齿 上一节我们了解了feign的主要功能&#xff0c;它就像一个自拍杆一样&#xff0c;方便了Eureka的远程调用。可是怎么看…

Feign 的实现原理

Feign 实现原理 Feign是申明式的 HTTP 客户端。代码中创建一个接口并加上FeingClient 注解即可使用。其底层封装了 HTTP 客户端构建并发送的复杂逻辑。同时也可以整合注册中心及 Ribbon 为其提供负载均衡能力&#xff1b;通过整合 Histrix/sentinal 实现熔断限流功能。本期主要…

OpenFeign的实现原理(附Feign和OpenFeign的区别)

目录 问题现象&#xff1a; 问题分析&#xff1a; 拓展&#xff1a; 1、Feign&#xff1a; 2、OpenFeign&#xff1a; 问题现象&#xff1a; 最近在复习SpringCloud的时候看到一个面试题&#xff1a; OpenFeign的实现原理&#xff1f; 问题分析&#xff1a; OpenFeign是Sp…

Feign原理

是一个HTTP请求调用轻量级框架&#xff0c;可以以Java接口注解的方式调用HTTP请求&#xff0c;而不用像Java中通过封装HTTP请求报文的方式直接调用。 Feign解决了什么问题 在服务调用的场景中&#xff0c;我们经常调用基于HTTP协议的服务&#xff0c;而我们经常使用到的框架可…

Feign的使用及原理剖析

feign使用及原理剖析 一、简介 Feign是一个http请求调用的轻量级框架&#xff0c;可以以Java接口注解的方式调用Http请求。Feign通过处理注解&#xff0c;将请求模板化&#xff0c;当实际调用的时候&#xff0c;传入参数&#xff0c;根据参数再应用到请求上&#xff0c;进而转…

Feign基本使用(超详细)

目录 一、Feign概述 二、Feign入门 1.创建服务提供者(provider) 2.创建feign接口 3、创建服务消费者(consumer) 三、Feign 原理 四、Feign优化 1、开启feign日志 2、feign超时问题 3、http连接池 4、gzip压缩 前言 当我们通过RestTemplate调用其它服务的API时&#xff0c;所…

简单理解Feign的原理与使用

文章目录 SpringCloud 总架构图一、简介1.1、负载均衡的概念2.2、Feign概念 二、入门案例2.1、导入依赖2.2、Feign的客户端2.3、调用Feign2.4、开启Feign功能2.5、启动测试2.6、Feign实现原理简单分析 三、负载均衡(Ribbon)四、熔断器支持五、请求压缩和响应压缩六、配置日志级…

【第四章】详解Feign的实现原理

1.1 Feign概述 这篇文章主要讲述如何通过Feign去消费服务&#xff0c;以及Feign的实现原理的解析。 Feign是Netflix开发的声明式、模板化的HTTP客户端&#xff0c;Feign可以帮助我们更快捷、优雅地调用HTTP API。 Feign是⼀个HTTP请求的轻量级客户端框架。通过 接口 注解的…

Feign底层原理分析-自动装载动态代理

本篇文章仅介绍Feign的核心机制&#xff0c;包括如何交由Spring容器托管、动态代理机制等内容&#xff0c;不会过分深入细节。 1、什么是Feign&#xff1f; 这里套用Feign官方Github上的介绍&#xff1a;“Feign是一个灵感来自于Retrofit、JAXRS-2.0、WebSocket的Java Http客户…