【OpenFeign】【源码+图解】【四】FeignClient实例工具类ReflectiveFeign

news2025/7/15 5:48:26

【OpenFeign】【源码+图解】【三】FeignClient的配置信息

目录

  • 5. FeignClient实例工具类ReflectiveFeign
    • 5.1 增强Builder属性
      • 5.1.1 Capability
    • 5.2 创建ReflectiveFeign

5. FeignClient实例工具类ReflectiveFeign

上文中调用了targeter.target(this, builder, context, target),其实DefaultTargeter的作用只是中转,没有做任何事情,如下图

在这里插入图片描述

因此我们就直接分析Feign$Builder.target()方法

public static class Builder extends BaseBuilder<Builder> {
    public <T> T target(Target<T> target) {
        // 1、先build()出Feign
        // 2、Feign.newInstance(target)
        return build().newInstance(target);
    }

    // 创建ReflectiveFeign,ReflectiveFeign用于创建OpenFeign接口的实例
    public Feign build() {
        // 1.1、增强Builder属性
        super.enrich();

        // 1.2、创建SynchronousMethodHandler.Factory
        SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
            new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
                                                 responseInterceptor, logger, logLevel, dismiss404, closeAfterDecode,
                                                 propagationPolicy, forceDecoding);
        // 1.3、创建ParseHandlersByName
        ParseHandlersByName handlersByName
            new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
                                    errorDecoder, synchronousMethodHandlerFactory);
        // 1.4、创建ReflectiveFeign
        return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
}

在这一节中主要分析build()步骤,这里分两步

5.1 增强Builder属性

5.1.1 Capability

在开始之前我们得先认识下Capability

在这里插入图片描述

从类图中可以看到,最终要的是enrich(Object componentToEnrich, Class<?> capabilityToEnrich, List<Capability> capabilities)方法,它的作用的给componentToEnrich对象添加上capabilitiescapabilityToEnrich功能,那么capabilityToEnrich都有哪些功能呢?看下Capability

在这里插入图片描述

以上就是能够添加的功能。为了能更好理解,我们举个例子

1、前面提到可以自己配置Capability,创建一个实现类MyCapability,给它添加一个实现方法,用来enrich当前Builder的Options属性

// 1、实现Capability接口
public class MyCapability implements Capability {

    // 2、覆盖enrich(Options options)方法
    @Override
    public Options enrich(Options options) {
        // 3、返回新建的Options, 设置connectTimeout为11, readTimeout为22
        return new Options(11, TimeUnit.SECONDS, 22, TimeUnit.SECONDS, false);
    }
    
}

2、在yml文件中配置

feign:
  client:
    config:
      product:
        capabilities: 
          - com.lanna.openfeign.custom.MyCapability

3、 在Builder类的第209行和211行打断点,重新启动,进入第一个断点时查看Builder的属性,如下图

在这里插入图片描述

经过super.enrich()后进入第二个断点

在这里插入图片描述

再查看Builder的属性,可见已经被更改了,说明MyCapability已经起作用。

上面介绍完Capability的作用,现在就该看看它的源码是怎么实现的了

public interface Capability {

    static Object enrich(Object componentToEnrich,
                         Class<?> capabilityToEnrich,
                         List<Capability> capabilities) {
        return capabilities.stream()
            .reduce( // reduce的功能类似foreach,在这里就是遍历capabilities逐个enrich
                componentToEnrich, // 初始值
                (target, capability) -> invoke(target, capability, capabilityToEnrich), // 累加器
                (component, enrichedComponent) -> enrichedComponent); // 最终值
    }

    static Object invoke(Object target, Capability capability, Class<?> capabilityToEnrich) {
        return Arrays.stream(capability.getClass().getMethods())
            .filter(method -> method.getName().equals("enrich")) // enrich方法
            .filter(method -> method.getReturnType().isAssignableFrom(capabilityToEnrich)) // 返回值是Builder中的参数类型
            .findFirst() 
            .map(method -> {
                try {
                    // method: MyCapability.enrich(feign.Request$Options)
                    // capability: MyCapability
                    // target: feign.Request$Options
                    return method.invoke(capability, target);
                } catch (IllegalAccessException | IllegalArgumentException
                         | InvocationTargetException e) {
                    throw new RuntimeException("Unable to enrich " + target, e);
                }
            })
            .orElse(target); // 没有enrich方法的话返回原值
    }
}

了解了Capability,对于Builder中的enrich就很好理解了

public abstract class BaseBuilder<B extends BaseBuilder<B>> {
    protected B enrich() {
        if (capabilities.isEmpty()) {
            // 如果没有capabilities直接返回
            return thisB;
        }

        // getFieldsToEnrich()获取需要增强的属性
        getFieldsToEnrich().forEach(field -> {
            field.setAccessible(true);
            try {
                // 1. 获取属性的值
                final Object originalValue = field.get(thisB);
                final Object enriched;
                // 2. 增强属性
                if (originalValue instanceof List) {
                    // 如果是列表的话先一个一个enrich再归纳,如requestInterceptors
                    Type ownerType = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
                    enriched = ((List) originalValue).stream()
                        .map(value -> Capability.enrich(value, (Class<?>) ownerType, capabilities))
                        .collect(Collectors.toList());
                } else {
                    // 给原始值originalValue添加capabilities功能
                    enriched = Capability.enrich(originalValue, field.getType(), capabilities);
                }
                field.set(thisB, enriched);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new RuntimeException("Unable to enrich field " + field, e);
            } finally {
                field.setAccessible(false);
            }
        });

        return thisB;
    }
}

5.2 创建ReflectiveFeign

public static class Builder extends BaseBuilder<Builder> {
    public Feign build() {
        // 1.1、
        super.enrich();

        // 1.2、创建SynchronousMethodHandler.Factory,将当前builder的参数赋给SynchronousMethodHandler.Factory
        SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
            new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
                                                 responseInterceptor, logger, logLevel, dismiss404, closeAfterDecode,
                                                 propagationPolicy, forceDecoding);
        // 1.3、创建ParseHandlersByName,将当前builder的参数赋给ParseHandlersByName
        ParseHandlersByName handlersByName
            new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
                                    errorDecoder, synchronousMethodHandlerFactory);
        // 1.4、创建ReflectiveFeign
        return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
}

ReflectiveFeign创建好后就开始下一章节的newInstance()

public static class Builder extends BaseBuilder<Builder> {
    public <T> T target(Target<T> target) {
        // 1、先build()出Feign
        // 2、Feign.newInstance(target)
        return build().newInstance(target);
    }
}

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

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

相关文章

【GO】 K8s 管理系统项目[API部分--Node]

K8s 管理系统项目[API部分–Node] 1. 接口实现 service/dataselector.go type nodeCell corev1.Nodefunc(n nodeCell) GetCreation() time.Time {return n.CreationTimestamp.Time }func(n nodeCell) GetName() string {return n.Name }2. Node功能 service/node.go 2.1 重…

基于Servlet 的Java Web项目的CSRF防御概念

本篇创建一个基本的Jave Web 项目, 使用Servlet提供服务, 使用Filter 处理CSRF防御。 演示环境 Java 1.8.0_211Eclipse 2021-06 (4.20.0)Maven 3.6Servlet 创建与运行 在Eclipse 中创建一个简单的Maven 项目, 项目名为 java-web,如下图: 创建完成的项目目录结构如下: 创…

pre compile header

预编译头文件存在的目的是减少一个项目中不经常改动的文件的编译次数&#xff1b; 打个比方&#xff1a;c标准库&#xff0c;当我们在项目中调用一个c标准库的时候&#xff0c;这个库一般是只读的&#xff0c;所以我们没必要每次编译项目的时候都recompile c标准库&#xff1b…

预约挂号系统技术点详解(二)

一、微服务间服务的调用介绍 1. 需求&#xff08;医院接口远程调用数据字典&#xff09; service-hosp服务调用service-cmn服务 2. 实现步骤 ⑴ 搭建service-client父模块 修改pom文件&#xff0c;添加需要使用的model模块和工具模块依赖&#xff0c;并添加openfeign依赖 …

Python学习笔记-PyQt

记述PyQt的相关基本知识。 一、PyQt概述 PyQt是一个创建GUI应用程序的工具包。它是Python编程语言和Qt库的成功融合。Qt库是最强大的库之一。PyQt是由Phil Thompson 开发。 PyQt实现了一个Python模块集。它有超过300类&#xff0c;将近6000个函数和方法。它是一个多平台的工…

使用 kube-prometheus(release-0.6) 监控 Kubernetes v1.18.20

本文档是使用 kube-prometheus-stack[release-0.6] 来监控 kubernetes1.18.20&#xff0c;具体兼容性可以看这里&#xff1a;https://github.com/prometheus-operator/kube-prometheus/tree/release-0.6#kubernetes-compatibility-matrix 1 概述 1.1 在 k8s 中部署 Prometheus…

SpringBoot任务调度(官方案例)

在线文档项目结构 1.源码克隆&#xff1a;git clone https://github.com/spring-guides/gs-scheduling-tasks.git 2.包含两个项目initial和complete&#xff0c;initial可以根据文档练习完善&#xff0c;complete是完整项目 3.功能描述&#xff1a;构建应用程序&#xff0c;使用…

数据结构 - AVL树 (Adelson-Velsky and Landis Tree)

目录一、前言二、简介三、左旋与右旋四、AVL树的调整1、向AVL树中插入新数据1&#xff09;LL型不平衡&#xff08;右单旋转&#xff09;2&#xff09;RR型不平衡&#xff08;左单旋转&#xff09;3&#xff09;LR型不平衡&#xff08;左右双旋转&#xff09;4&#xff09;RL型不…

爆款短视频是怎样练成的:视频发布技巧,首次公开

剪辑好的优质短视频怎么发布才能成为爆款视频&#xff1f;短视频发布技巧公开 前面几篇我们讨论了短视频定位&#xff0c;怎么写文案脚本&#xff0c;怎么拍摄以及后期剪辑&#xff0c;至此我们一个优质的短视频已经制作完成&#xff0c;今天我们就聊一下下一个环节&#xff1…

Kafka Producer Retries Idempotence 原理

Kafka Producer Retries & Idempotence 原理 由于存在网络瞬时抖动&#xff1b;或者kafka集群短暂的不可用&#xff0c;会导致kafka producer发送消息出现异常&#xff0c;生产者无法将消息推送到topic&#xff0c;在这种情况下&#xff0c;消息丢失的可能性很高。因此kaf…

全排列思路

目录 省流版结论 推导过程 输出结果&#xff08;元素数量为4时&#xff09; 省流版结论 &#xff08;程序来源&#xff1a;排列组合之——全排列&#xff08;c语言&#xff09;_rewrite!的博客-CSDN博客_全排列&#xff09; 一晚上的时间&#xff0c;终于弄懂了。真羡慕计算…

基于标志点特征高精提取与匹配方法,进行双目、结构光、RGBD相机、单目相机多视拼接

1. 工作原理 人工张贴标志点变换位置拍照相邻照片的公共视野内有相同的标志点群匹配两张照片对应标志点对通过三对以上标志点对&#xff0c;实现两张照片间的坐标变换求解 2.标志点特征 圆形 分类&#xff1a; 编码&#xff08;粘贴于被测物体表面&#xff09;&#xff1a;…

SpringBoot文件上传(官方案例)

在线文档项目结构 1.源码克隆&#xff1a;git clone https://github.com/spring-guides/gs-uploading-files.git 2.包含两个项目initial和complete&#xff0c;initial可以根据文档练习完善&#xff0c;complete是完整项目 3.功能描述&#xff1a;构建接受文件上传的应用程序&a…

转行人必看:数字IC前端设计学习路线与方法(内附学习视频)

众所周知&#xff0c;数字前端设计对于工程师的能力要求比较高&#xff0c;不仅有学历上的要求&#xff0c;还要求掌握很多的知识技能。不少跨专业想要转行的小伙伴对数字前端设计这个岗位不是很了解&#xff0c;下面IC修真院就带大家全面了解一下数字IC前端设计。 数字前端到…

酒水销售网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 网站前台&#xff1a;网站介绍、帮助信息、酒水资讯、酒水类型、酒水信息、购物分享 管理员&#xff1a; 1、管理网站介…

matlab源码说明

目录 1.MATLAB概述 2.MATLAB程序使用几个常规注意实现 2.1.运行过程可能出现Out of Memory的问题解决办法 2.2.保存大于2G的数据 2.3.程序运行方法 1.MATLAB概述 Matlab经过不断的发展和完善,如今已成为覆盖多个学科,是具有超强数值计算能力和仿真分析能力的软件。…

YOLOv5s.yaml文件解读

目录一、YOLOv5s.yaml内容二、详解2.1参数配置2.2 anchors2.3 backbone2.4 head三、如何调整模型一、YOLOv5s.yaml内容 YOLOv5配置了4种不同大小的网络模型&#xff0c;分别是YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x&#xff0c;其中YOLOv5s是网络深度和宽度最小但检测速度最快的…

资深车主才会告诉你的那些事,看完立省三万二

自动驾驶已经火了几年了。在某度一搜“自动驾驶”&#xff0c;全都是某某公司推出了自动驾驶&#xff0c;某某公司打算推出自动驾驶。当然&#xff0c;这两年因为各种事故的原因&#xff0c;“自动驾驶”被各种名词取代——辅助驾驶、高级辅助驾驶、领航辅助驾驶......这就有点…

以英雄之名为S9总决赛助攻! 虎牙直播and华为云CDN,team work才会赢

以英雄之名为S9总决赛助攻! 虎牙直播and华为云CDN&#xff0c;team work才会赢 你的朋友圈肯定经历过这样一波刷屏 啊啊!!!赢了祝贺!#FPX团灭G2#FPX夺冠啦!超帅超酷超级棒!我们是冠军!!!恭喜FPX!凤凰涅槃!FPX咋这么稳!实在太稳了!小凤凰一飞冲天 团灭!就两个字 就是感觉很厉害…

SimpleAdapter的简单使用

SimpleAdapter适配器的简单使用 1.SimpleAdapter 1.简介 显示复杂的列表项&#xff0c;如图片2.SimpleAdapter的构造函数 上下文数据&#xff08;保存map的list集合&#xff09;子布局key子布局中的id注意&#xff1a;key和id是一一对应的关系 3.SimpleAdapter案例-用户简介 3.…