Feign代理目标方法执行流程

总体而言Feign调用目标方法之前被jdk动态代理区分为两种形式:负载均衡方式以及域名直接调用方式。

public class FeignClientFactoryBean{public <T> T getTarget() {//通过父容器创建子容器工厂类FeignContextFeignContext context = applicationContext.getBean(FeignContext.class);// 通过子容器 FeignContext 为每个Feign客户端创建 Feign.BuilderFeign.Builder builder = feign(context);//如果FeignClient注解存在URL配置则直接调用,否则通过ribbon负载均衡if (!StringUtils.hasText(this.url)) {...HardCodedTarget target = new HardCodedTarget<>(this.type, this.name, this.url);// 通常选择负载均衡方式return (T) loadBalance(builder, context, target);}...String url = this.url + cleanPath();// LazyTracingFeignClientClient client = getOptional(context, Client.class);if (client != null) {if (client instanceof FeignBlockingLoadBalancerClient) {client = ((FeignBlockingLoadBalancerClient) client).getDelegate();}if (client instanceof RetryableFeignBlockingLoadBalancerClient) {client = ...}builder.client(client);}applyBuildCustomizers(context, builder);Targeter targeter = get(context, Targeter.class);HardCodedTarget target = new HardCodedTarget<>(this.type, this.name, this.url);return (T) targeter.target(this, builder, context,target);//域名调用方式}
}

 HardCodedTarget中其中type是指Feign客户端接口类型。注意区别于Targeter。


1.负载均衡之TraceFeignBlockingLoadBalancerClient

该方式适用于服务治理过程中,代理的原因是为了真正调用目标方法之前完成服务端负载均衡策略。

public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean {protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) {Client client = getOptional(context, Client.class);//TraceFeignBlockingLoadBalancerClient || LoadBalancerFeignClient,区别于域名调用方式client之LazyTracingFeignClientif (client != null) {builder.client(client);applyBuildCustomizers(context, builder);//扩展点Targeter targeter = get(context, Targeter.class);//从子容器获取 FeignCircuitBreakerTargeterreturn targeter.target(this, builder, context, target);}}
}

1.1.FeignCircuitBreakerTargeter

class FeignCircuitBreakerTargeter implements Targeter {public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,FeignContext context,Target.HardCodedTarget<T> target) {// 如果没有显式设置 HystrixFeign 的开关,默认Builder 为 抽象类Feign内部静态类if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {return feign.target(target);// 忽略Feign降级功能}FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName(): factory.getContextId();Class<?> fallback = factory.getFallback();if (fallback != void.class) {// 优先通过Fallback实现Feign降级功能return targetWithFallback(name, context, target, builder, fallback);}Class<?> fallbackFactory = factory.getFallbackFactory();if (fallbackFactory != void.class) {// 其次通过FallbackFactory实现Feign降级功能return targetWithFallbackFactory(name, context, target, builder,fallbackFactory);}return feign.target(target);// 忽略Feign降级功能}private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,Target.HardCodedTarget<T> target,FeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {// 服务熔断或者降级工厂类FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory",feignClientName, context, fallbackFactoryClass, FallbackFactory.class);return builder(feignClientName, builder).target(target, fallbackFactory);}private FeignCircuitBreaker.Builder builder(String feignClientName, FeignCircuitBreaker.Builder builder) {// 初始化 Feign.Builder 相关的一些参数return builder.circuitBreakerFactory(circuitBreakerFactory).feignClientName(feignClientName)//feign.circuitbreaker.group.enabled配置.circuitBreakerGroupEnabled(circuitBreakerGroupEnabled).circuitBreakerNameResolver(circuitBreakerNameResolver);}
}
public final class FeignCircuitBreaker {public static Builder builder() {return new Builder();}public static final class Builder extends Feign.Builder {private CircuitBreakerFactory circuitBreakerFactory;private String feignClientName;private boolean circuitBreakerGroupEnabled;...public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {// 利用ReflectiveFeign完成当前Feign客户端的jdk动态代理return build(fallbackFactory).newInstance(target);}public Feign build(final FallbackFactory<?> nullableFallbackFactory) {// 初始化抽象类 Feign.Builder 相关的一些参数super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,circuitBreakerGroupEnabled, circuitBreakerNameResolver));//初始化抽象类 Feign.Builder父类BaseBuilder 相关的一些参数return super.build();}}}

 FeignCircuitBreakerInvocationHandler是JDK动态代理中设置处理器InvocationHandler。

public abstract class Feign {public static class Builder extends BaseBuilder<Builder> {public Feign build() {super.enrich();SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,responseInterceptor, logger, logLevel, dismiss404, closeAfterDecode,propagationPolicy, forceDecoding);ParseHandlersByName handlersByName =new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,errorDecoder, synchronousMethodHandlerFactory);// invocationHandlerFactory抽象类 Feign.Builder父类BaseBuilder的属性之FeignCircuitBreakerInvocationHandlerreturn new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);}}}
}

1.2.ReflectiveFeign之jdk动态代理

public class ReflectiveFeign extends Feign {@Overridepublic <T> T newInstance(Target<T> target) {//解析当前Feign客户端所有方法,将每个方法抽象为 SynchronousMethodHandlerMap<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();for (Method method : target.type().getMethods()) {if (method.getDeclaringClass() == Object.class) {continue;} else if (Util.isDefault(method)) {DefaultMethodHandler handler = new DefaultMethodHandler(method);defaultMethodHandlers.add(handler);methodToHandler.put(method, handler);} else {methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));}}// FeignCircuitBreakerInvocationHandler:将目标方法抽象体SynchronousMethodHandler 跟 InvocationHandler建立绑定关系InvocationHandler handler = factory.create(target, methodToHandler);T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),new Class<?>[] {target.type()}, handler);for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {defaultMethodHandler.bindTo(proxy);}return proxy;}
}

 至此,利用JDK动态代理完成每个Feign客户端实例的创建。


2.域名调用方式之LazyTracingFeignClient


3.执行目标方法的代理过程


4.Feign & Builder关系

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/641236.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Oracle] INSERT INTO 几种用法

插入数据需要使用 INSERT INTO 语句。该语句有多种写法&#xff0c;具体取决于插入的数据来源和目标&#xff0c;下面介绍一些常见用法和语法。 1.插入所有列的值 如果要将数据插入到表中的所有列中&#xff0c;则可以使用以下 INSERT INTO 语句&#xff1a; INSERT INTO tab…

ARM_Linux中GCC编译器的使用

目录 前言: GCC编译过程: 预处理&#xff1a; 编译阶段&#xff1a; 汇编&#xff1a; 链接阶段 GCC的常见使用 前言: 什么是GCC: gcc的全称是GNU Compiler Collection&#xff0c;它是一个能够编译多种语言的编译器。最开始gcc是作为C语言的编译器&#xff08;GNU C Co…

PgSQL - 17新特性 - 块级别增量备份

PgSQL - 17新特性 - 块级别增量备份 PgSQL可通过pg_basebackup进行全量备份。在构建复制关系时&#xff0c;创建备机时需要通过pg_basebackup全量拉取一个备份&#xff0c;形成一个mirror。但很多场景下&#xff0c;我们往往不需要进行全量备份/恢复&#xff0c;数据量特别大的…

C++面试宝典第23题:乌托邦树

题目 乌托邦树每年经历2个生长周期。每年春天,它的高度都会翻倍。每年夏天,他的高度都会增加1米。对于一颗在春天开始时种下的高为1米的树,问经过指定周期后,树的高度为多少? 输入描述:输入一个数字N(0 <= N <= 1000),表示指定周期。 比如:样例输入为3。 输出描…

helm---自动化一键部署

什么是helm?? 在没有这个helm之前&#xff0c;deployment service ingress helm的作用就是通过打包的方式&#xff0c;把deployment service ingress 这些打包在一块&#xff0c;一键式部署服务&#xff0c;类似于yum 官方提供的一个类似于安装仓库的功能&#xff0c;可以实…

基于springboot+vue新能源汽车充电管理系统

摘要 新能源汽车充电管理系统是基于Spring Boot和Vue.js技术栈构建的一款先进而高效的系统&#xff0c;旨在满足不断增长的新能源汽车市场对充电服务的需求。该系统通过整合前后端技术&#xff0c;实现了用户注册、充电桩管理、充电订单管理等核心功能&#xff0c;为用户提供便…

vue的vue-resource和axios介绍

在Vue项目中前后端交互时&#xff0c;早期Vue使用Vue-resource实现异步请求。 从Vue2.0之后就不再对vue-resource进行更新&#xff0c;Vue官方推荐使用axios。 一、vue-resource Vue.js的插件提供了使用XMLHttpRequest 或 JSONP进行Web请求和处理响应的服务。vue-resource像jQ…

使用DTS实现TiDB到GaiaDB数据迁移

1 概览 本文主要介绍通过 DTS 数据迁移功能&#xff0c;结合消息服务 for Kafka 与 TiDB 数据库的 Pump、Drainer 组件&#xff0c;完成从TiDB迁移至百度智能云云原生数据库 GaiaDB。 消息服务 for Kafka&#xff1a;详细介绍参见&#xff1a;消息服务 for Kafka 产品介绍百度智…

go 语言中 json.Unmarshal([]byte(jsonbuff), j) 字节切片得使用场景

struct_tag的使用 在上面的例子看到&#xff0c;我们根据结构体生成的json的key都是大写的&#xff0c;因为结构体名字在go语言中不大写的话&#xff0c;又没有访问权限&#xff0c;这种问题会影响到我们对json的key的名字&#xff0c;所以go官方给出了struct_tag的方法去修改…

R语言rvest爬虫如何设置ip代理?

前言 在R语言中使用rvest进行网络爬虫时&#xff0c;可以使用代理服务器来隐藏真实IP地址。有一些R包可以帮助爬虫中设置代理&#xff0c;其中一个常用的包是httr。以下是一个简单的例子&#xff0c;演示如何在rvest中设置IP代理 教程 一、获取代理IP并提取 二、详情设置 l…

golang常用库之-golang-jwt/jwt包

文章目录 golang常用库之-golang-jwt/jwt包golang-jwt/jwt包使用demo golang常用库之-golang-jwt/jwt包 golang-jwt/jwt包 github&#xff1a; https://github.com/golang-jwt/jwt golang-jwt/jwt 是一个在 Go 语言中使用 JSON Web Tokens&#xff08;JWT&#xff09;进行身…

2024三掌柜赠书活动第四期: Next.js实战,构建现代化的可扩展Web应用

目录 摘要前言Next.js简介关于《 Next.js实战》实战示例最佳实践和进阶应用编辑推荐内容简介作者简介图书目录书中前言/序言《Next.js实战》全书速览结束语 摘要&#xff1a;本文将介绍Next.js&#xff0c;一个流行的React框架&#xff0c;以及如何在实际项目中使用Next.js构…

Linux中timerfd系列函数使用指南

timerfd_create, timerfd_settime, timerfd_gettime系列函数将定时器的实现与文件描述符绑定在一起&#xff0c;定时器超时的那一刻文件描述符变得可读&#xff0c;因此可以很好的与 select、poll 和 epoll 结合在一起使用。 timerfd_create 系统调用将创建一个定时器并与一个…

OSPF协议LSDB同步过程和邻居状态机

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

技术型企业如何选择安全、性价比高的FTP替代方案?

FTP作为世界上第一款文件传输协议&#xff0c;在全球范围内应用广泛&#xff0c;它解决了文件传输协议空白的问题&#xff0c;为文件传输场景提供了专业的解决方案。 但随着网络技术的演进&#xff0c;技术型企业进行文件传输的需求也更多元和复杂&#xff0c;FTP的缺陷也更多的…

Flutter中的AppLifecycleListener:应用生命周期监听器介绍及使用

引言 当你在Flutter中需要监听应用程序的生命周期变化时&#xff0c;可以使用AppLifecycleListener。在Flutter 3.13中&#xff0c;AppLifecycleListener被添加到Framework中&#xff0c;用于监听应用程序的生命周期变化&#xff0c;并响应退出应用程序的请求等支持。 在Flut…

CmakeList教程

一、CmakeList介绍&#xff1a; cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。它会通过写的语句自动生成一个MakeFile,从而实现高效编译 二、CmakeList的常用指令 1.指定…

【 CSS 】定位

不要因为小小的失败而放弃大大的梦想&#xff0c;每一次坚持都是通向成功的一步。- 马克吐温 1. 定位 1.1 为何使用定位 我们先来看一个效果&#xff0c;同时思考一下用标准流或浮动能否实现类似的效果&#xff1f; 场景1: 某个元素可以自由的在一个盒子内移动位置&#xff0c…

#Uniapp:uni.request(OBJECT)

uni.request(OBJECT) 发起网络请求。 示例 uni.request({url: https://www.example.com/request, //仅为示例&#xff0c;并非真实接口地址。data: {text: uni.request},header: {custom-header: hello //自定义请求头信息},success: (res) > {console.log(res.data);thi…

微服务基础概念、架构图、划分图

基础概念 1、微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个小服务运行在自己的进程中&#xff0c;并使用轻量级机制通信&#xff0c;通常是http api。这些服务围绕业务能力来构建。并…