OpenFeign 自定义解码器Decoder 失效
问题描述
项目上开发了OpenFeign的自定义解码器,用来统一处理返回结果。
开发完后测试已经生效了,过两天后,这块代码没有变动的情况下,发现请求结果突然又不走自定义的解码器了。
代码如下
解码器 BaseResponseFeignDecoder
@Slf4j
public class BaseResponseFeignDecoder implements Decoder {static ObjectMapper objectMapper = new ObjectMapper();static {objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}@Overridepublic Object decode(Response response, Type type) throws IOException, FeignException {if (response.body() == null) {throw new DecodeException(response.status(), "没有返回有效的数据", response.request());}String bodyStr = Util.toString(response.body().asReader(Util.UTF_8));//对结果进行转换TypeFactory typeFactory = objectMapper.getTypeFactory();JavaType resultType = typeFactory.constructParametricType(BaseResponse.class, typeFactory.constructType(type));BaseResponse<?> result = objectMapper.readValue(bodyStr, resultType);//如果返回错误,且为内部错误,则直接抛出异常if (!BaseConstants.HTTP_RESPONSE_CODE_SUCCESS.equals(result.getCode())) {throw new DecodeException(response.status(), "接口返回错误:" + result.getMsg(), response.request());}return result.getData();}
}
配置类 BaseResponseFeignConfig
public class BaseResponseFeignConfig {@Beanpublic Decoder feignDecoder() {return new BaseResponseFeignDecoder();}}
Feign接口定义 FinValidationFeign
@FeignClient(name = "masterdata", path = "/api/validation", configuration = BaseResponseFeignConfig.class)
public interface FinValidationFeign {// 各类feign接口
}
问题排查
由于当前代码没有变动,怀疑是解码器被别人的新开发的代码给覆盖了。但排查之后项目里并没有其他解码器相关的代码。
只能跟踪解码器的加载进行排查。
OpenFeign客户端会在应用启动时进行加载。
根据 FeignClient 注解跟踪到 org.springframework.cloud.openfeign.FeignClientsRegistrar 的 registerFeignClients 方法。
我们可以看到加载时,通过registerClientConfiguration 方法加载自定义配置
通过代码可以看到注册的 beanName 为 name + "." + FeignClientSpecification.class.getSimpleName(), 也就是 masterdata.feignClientSpecification
由此可以看出当多个Client 的 name 一致时,会使用最后一个加载的client的配置。
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");if (clients == null || clients.length == 0) {ClassPathScanningCandidateComponentProvider scanner = getScanner();scanner.setResourceLoader(this.resourceLoader);scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));Set<String> basePackages = getBasePackages(metadata);// 通过扫包将 FeignClient 注解的代码都加载出来for (String basePackage : basePackages) {candidateComponents.addAll(scanner.findCandidateComponents(basePackage));}}else {for (Class<?> clazz : clients) {candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));}}// 循环初始化Feign客户端for (BeanDefinition candidateComponent : candidateComponents) {if (candidateComponent instanceof AnnotatedBeanDefinition) {// verify annotated class is an interfaceAnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");// 加载 FeignClient 注解的参数Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());String name = getClientName(attributes);// 处理自定义配置, 默认值 {}, 无自定义配置也会走这步registerClientConfiguration(registry, name, attributes.get("configuration"));registerFeignClient(registry, annotationMetadata, attributes);}}
}private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);builder.addConstructorArgValue(name);builder.addConstructorArgValue(configuration);// 根据name + FeignClientSpecification 进行Spring的Bean注册registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
}
这时候再扭头过来看这两天加的代码,发现新增了一个 同名name的client,并且没配置自定义解码器,加载顺序在 FinValidationFeign 之后,导致他的配置覆盖掉了 FinValidationFeign 。一起变成了走默认的解码器。
@FeignClient(name = "masterdata", path = "/api/query")
public interface FinQueryFeign {// 各类feign接口
}
解决方案
因为对应服务在重构,返回值存在两个包装类,没办法进行统一配置。
因为是beanName相同导致的配置覆盖,而我们能修改的name是通过 String name = getClientName(attributes); 获取的
可以看到 name 是优先获取 contextId , 我们可以通过配置contextId进行区分,避免覆盖。
private String getClientName(Map<String, Object> client) {if (client == null) {return null;}String value = (String) client.get("contextId");if (!StringUtils.hasText(value)) {value = (String) client.get("value");}if (!StringUtils.hasText(value)) {value = (String) client.get("name");}if (!StringUtils.hasText(value)) {value = (String) client.get("serviceId");}if (StringUtils.hasText(value)) {return value;}throw new IllegalStateException("Either 'name' or 'value' must be provided in @" + FeignClient.class.getSimpleName());}
解决后的代码
@FeignClient(name = "masterdata", contextId = "masterdata-validation", path = "/api/validation", configuration = BaseResponseFeignConfig.class)
public interface FinValidationFeign {// 各类feign接口
}
相关文章:
OpenFeign 自定义解码器Decoder 失效
问题描述 项目上开发了OpenFeign的自定义解码器,用来统一处理返回结果。 开发完后测试已经生效了,过两天后,这块代码没有变动的情况下,发现请求结果突然又不走自定义的解码器了。 代码如下 解码器 BaseResponseFeignDecoder …...
c++练习题8
1.在do-while循环中,循环由do开始,用while结束;必须注意的是:在while表达式后面的 不能丢,它表示do-while语句的结束。 A)0 B)1 C);…...
Python循环语句代码详解:while、for、break
目录 1 while循环 1 while循环 循环语句是程序设计中常用的语句之一。任何编程语言都有while循环,Python也不例外。while循环的格式如下所示。 while(表达式): … else: … while循环的执行过程:当循环表达式为真时,依次执行whi…...
vue父子组件传值不能实时更新
最近做项目,遇到个大坑,这会爬出来了,写个总结,避免下次掉坑。 vue父子组件传值不能实时更新问题,父组件将值传给了子组件,但子组件显示的值还是原来的初始值,并没有实时更新,为什么…...
2023美赛A题思路数据代码分享
文章目录赛题思路2023年美国大学生数学建模竞赛选题&论文一、关于选题二、关于论文格式三、关于论文提交四、论文提交流程注意不要手滑美赛A题思路数据代码【最新】赛题思路 (赛题出来以后第一时间在CSDN分享) 最新进度在文章最下方卡片,加入获取一手资源 202…...
【蓝桥杯集训·每日一题】AcWing 3768. 字符串删减
文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴双指针一、题目 1、原题链接 3768. 字符串删减 2、题目描述 给定一个由 n 个小写字母构成的字符串。 现在,需要删掉其中的一些字母,使得字符串中不…...
Python|每日一练|树|深度优先搜索|数组|二分查找|链表|双指针|单选记录:填充每个节点的下一个右侧节点指针|搜索插入位置|旋转链表
1、填充每个节点的下一个右侧节点指针(树,深度优先搜索) 给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下: struct Node { int val; Node *left; Node *rig…...
降雨量实时监测系统压电式雨量计
压电式雨量传感器由上盖、外壳和下盖组成,壳体内部有压电片和电路板,可以固定在外径50mm立柱上和气象站横杆上。传感器采用冲击测量原理对单个雨滴重量进行测算,进而计算降雨量。雨滴在降落过程中受到雨滴重量和空气阻力的作用,到…...
滑动相关的原理以及用滤波器实现滑动相关(匹配滤波器捕获DMF)
目录滑动相关匹配滤波器捕获(DMF)滑动相关 滑动相关属于一种时域捕获方法,其具体原理是是通过本地序列与接收信号在固定窗长内滑动累加得到相关结果。 一般滑动相关算法可以用于对自相关性非常好的伪码进行同步判决。 我们首先生成一组自相关…...
计算机网络笔记(三)—— 数据链路层
数据链路层概述 数据链路层以帧为单位传输数据。 封装成帧:给网络层提供的协议数据单元添加帧头帧尾 差错检测:检错码封装在帧尾 可靠传输:尽管误码不能避免,但如果可以实现发送什么就接受什么,就叫可靠传输 封装成…...
【日常】矩阵正态分布参数检验问题
最近给凯爹做的一个苦力活,统计检验这个东西说实话也挺有趣,跟算法设计一样,好的检验真的是挺难设计的,就有近似算法的那种感觉,检验很难保证size和power都很理想,所以就要做tradeoff,感觉这个假…...
QML矩形(Rectangle)
Rectangle 用于绘制矩形 常见的属性: 填充颜色:纯色:color 渐变 :Gradient类 渐变的优先级大于纯色Gradient(渐变色): 渐变由多种颜色定义,这些颜色将无缝混合,…...
CSS自定义鼠标样式
CSS自定义鼠标样式 属性值 属性描述url需使用的自定义光标的 URLdefault默认光标(通常是一个箭头)auto默认。浏览器设置的光标crosshair光标呈现为十字线pointer光标呈现为指示链接的指针(一只手)move此光标指示某对象可被移动e…...
春招Leetcode刷题日记-D4-双指针算法-滑动窗口快慢指针
D4-双指针算法-滑动窗口&&快慢指针快慢指针算力扣141. 环形链表思路代码力扣142. 环形链表 II思路代码滑动窗口力扣76. 最小覆盖子串思路代码力扣424. 替换后的最长重复字符思路代码快慢指针算 快慢指针算法,多用于链表当中,常见的如࿱…...
【go】结合一个go开源项目分析谷歌浏览器cookie为什么不安全 附go项目导包失败怎么解决教程
本文创作背景 源于谷歌浏览器提示密码被泄露 并且某站很快收到了异地企图登录的提醒。 当即怀疑是不是谷歌浏览器保存的密码不安全,最后查阅诸多资料 并找到一个go语言编写的开源项目进行研究,虽然最终不能确定密码是如何泄露的 但研究结论还是让人不由感…...
Windows瘦身方法
一、快速删除系统盘临时文件方法, 1、winr打开运行对话框,输入%temp%命令,如图1 图1 2、打开temp文件夹,如图2,选择所有文件,鼠标右键删除或按Del键删除。 图2 二、磁盘清理 1、winr,输入cleanmgr&#x…...
19. 删除链表的倒数第 N 个结点
题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/进阶:你能尝试使用一趟扫描实现吗?解题思路:最简单的方法是先遍历一次链表,得到链表的长度len,然后再一次遍历链表,遍…...
【Linux】网络编程 - 基础概念
目录 一.OSI七层模型vsTCP/IP五层模型 1.一些周边概念 2.OSI七层模型 3.TCP/IP五层模型 4.网络传输流程图 二.什么是MAC地址 三.什么是IP/IP地址 1.什么是IP 2.什么是IP地址 四.什么是端口号 一.OSI七层模型vsTCP/IP五层模型 1.一些周边概念 局域网vs广域网 网络互…...
Unity 多语言 轻量高效的多语言工具集 LanguageManager
效果展示 支持excel导入自动化 组件化 更方便 也提供直接获取多语言的接口 没有挂 LanguageText的对象也可以获取多语言文本内容 支持 Format接口 可以传递N个参数进来组装多语言 支持首次系统语言自测 支持语言切换后本地自动保存配置 支持实时切换 同步刷新所有UI 容错处…...
在Linux和Windows上安装zookeeper-3.5.9
记录:378场景:在CentOS 7.9操作系统上,安装zookeeper-3.5.9。在Windows上操作系统上,安装zookeeper-3.5.9。版本:JDK 1.8 CentOS 7.9 zookeeper-3.5.9官网地址:https://zookeeper.apache.org/源码地址&…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
