spring cloud openfeign 使用注意点

近期在做项目时给自己挖了一个坑,问题重现如下

使用的组件版本如下

spring boot 2.7.15,对应的 spring cloud 版本为 2021.0.5,其中 spring cloud 适配的 openfeign 版本是 3.1.5。

项目中使用的 feign 接口如下

public interface QueryApi {/*** 符合查询条件数据总数* @return*/@PostMapping(value = "count")default CommonResponse count(@RequestParam(value = "indexName", required = true) @RequestParameterValue String indexName,@RequestParam(value = "queryFieldConditions", required = false) @Separator List<String> queryFieldConditions) {return null;}
}

乍看没什么问题,只是加了一个 default 关键字,使用 java 8 的特性,java 的 interface 类型中的方法默认是 public abstract 的。

但是到了别的服务调用时就出现问题了,自己之前写的 feign 接口没问题,写法也类似,区别就是加了一个 default 关键字。

想不明白怎么就加了一个关键字就不行了,是哪里的逻辑判断的问题?

本着找问题到底的想法,在方法调用时跟进源码,发现在 ReflectiveFeign 中进了下图中的逻辑

进入 Util.isDefault() 中发现

通过与、或、且、相等四种运算判断了当前方法是否为 default。

写例子看一下加 default 和不加 default 的区别

不加 default 查看修饰符的和

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;public class NoDefaultTest {public static void main(String[] args) {System.out.println("Modifier.SYNTHETIC " + 0x00001000);System.out.println("Modifier.ABSTRACT " + Modifier.ABSTRACT);System.out.println("Modifier.PUBLIC " + Modifier.PUBLIC);System.out.println("Modifier.STATIC " + Modifier.STATIC);int no = (Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT | 0x00001000);System.out.println(no);int temp = 1 & no;System.out.println(temp);System.out.println("+++++++++++++++++++++++++++++++++++++++++++");Class<QueryApi> configurerClass = QueryApi.class;List<Method> methodList = Arrays.asList(configurerClass.getMethods());for (Method method : methodList) {System.out.println(method.getDeclaringClass().isInterface());System.out.println(method.getModifiers());}}
}

执行结果

Modifier.SYNTHETIC 4096
Modifier.ABSTRACT 1024
Modifier.PUBLIC 1
Modifier.STATIC 8
5129
1
+++++++++++++++++++++++++++++++++++++++++++
true
1025

可以发现,不加 default 的方法修饰符值为1025,即 public 和 abstract 的组合

加 default 查看修饰符的和

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;public class DefaultTest {public static void main(String[] args) {System.out.println("Modifier.SYNTHETIC " + 0x00001000);System.out.println("Modifier.ABSTRACT " + Modifier.ABSTRACT);System.out.println("Modifier.PUBLIC " + Modifier.PUBLIC);System.out.println("Modifier.STATIC " + Modifier.STATIC);int no = (Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT | 0x00001000);System.out.println(no);int temp = 1 & no;System.out.println(temp);System.out.println("+++++++++++++++++++++++++++++++++++++++++++");Class<QueryApi> configurerClass = QueryApi.class;List<Method> methodList = Arrays.asList(configurerClass.getMethods());for (Method method : methodList) {System.out.println(method.getDeclaringClass().isInterface());System.out.println(method.getModifiers());}}
}

执行结果

Modifier.SYNTHETIC 4096
Modifier.ABSTRACT 1024
Modifier.PUBLIC 1
Modifier.STATIC 8
5129
1
+++++++++++++++++++++++++++++++++++++++++++
true
1

可以发现,加 default 的方法修饰符值为1,即 public

以方法不加 default 修饰符来验证逻辑

判断代码为

((method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC)&& method.getDeclaringClass().isInterface()

下面拆开来验证

第一步

进行或运算使四个数相加

Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC

最终结果为 5129。接下来进行与运算

第二步

method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)

鉴于上面验证的不加 default 的方法修饰符值为1025,转二进制后为 1001

1 0100 0000 10011001

两者计算结果为 1001,接下来与 Modifier.PUBLIC 进行等值比较

第三步

((method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC)

由于 Modifier.PUBLIC 为1,所以两数不相等,后面还要跟当前方法所在类是否是接口进行且运算

第四步

method.getDeclaringClass().isInterface()

鉴于前面的判断为 false,后面为 true,所以结果为 false。

所以 Util.isDefault() 执行结果为 false,执行最后的 else 逻辑。

最终使用 jdk 的动态代理进行调用 MethodHandler 的实现类  SynchronousMethodHandler 来处理请求。

以方法加 default 修饰符来验证逻辑

从第二步来讲

 第二步

method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)

鉴于上面验证的加 default 的方法修饰符值为1,转二进制还是 1

1 0100 0000 10011

两者计算结果为 1,接下来与 Modifier.PUBLIC 进行等值比较

第三步

((method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC)

由于 Modifier.PUBLIC 为1,所以两数相等,后面还要跟当前方法所在类是否是接口进行且运算

第四步

method.getDeclaringClass().isInterface()

鉴于前面的判断为 true,后面为 true,所以结果为 true。

最终调用 MethodHandler 的实现类 DefaultMethodHandler 来处理请求。

实际在调用 invoke() 的过程中没有执行结果,是 feign 针对 default 修饰的方法的一个 bug 还是我的调用方式有问题?

总结

定义的接口类中的方法中,修饰符是否添加有下面的情况

  1. 如果不声明修饰符,默认是 public abstract,对应的值为 1025。
  2. 如果声明修饰符 default,默认是 public,对应的值为 1。

为了防止 feign 调用出现一些其他未知的问题,还是不添加修饰符为好。

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

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

相关文章

C语言--写一个函数返回bool值,来判断给定的字符串A和B(假设都是小写字母),是否是B中的字符都存在于A中,如果是返回true,否则返回false

一.题目描述 写一个函数返回bool值&#xff0c;来判断给定的字符串A和B&#xff08;假设都是小写字母&#xff09;&#xff0c;是否是B中的字符都存在于A中&#xff0c;如果是返回true&#xff0c;否则返回false。例如&#xff1a; 字符串A&#xff1a;abcde 字符串B&#xff…

Java爬取哔哩哔哩视频(可视化)

链接&#xff1a;我的讲解视频https://www.bilibili.com/video/BV14e411Q7oG/ 本文仅供学术用途 先上图 代码 爬虫核心 import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.gargoylesoftware.htmlunit.*; import org.apache.commons.…

ubuntu22.04下hadoop3.3.6+hbase2.5.6+phoenix5.1.3开发环境搭建

一、涉及软件包资源清单 1、java 这里使用的是openjdk 2、hadoop-3.3.6.tar.gz 3、hbase-2.5.6-hadoop3-bin.tar.gz 4、phoenix-hbase-2.5-5.13-bin.tar.gz 5、apache-zookeeper-3.8.3-bin.tar.gz 6、openssl-3.0.12.tar.gz 二、安装 1、操作系统环境准备 换源 sudo vim /et…

【MySQL】MVCC(多版本并发控制)详解

MVCC MVCC概述 MVCC&#xff0c;全称 Multi-Version Concurrency Control &#xff0c;即多版本并发控制。MVCC 是一种并发控制的方法&#xff0c;一般在数据库管理系统中&#xff0c;实现对数据库的并发访问&#xff0c;在编程语言中实现事务内存。 MVCC就是在ReadCommitte…

国民技术Cortex-M0系列单片机IAP升级

考虑到设备部署到现场后有可能需要进行软件升级&#xff0c;之前做过PIC系列单片机的升级&#xff0c;现在想做个国民技术N32G031系列Cortex-M0内核的单片机IAP方案。 因为国民技术系列单片机在很多大程度上都模仿了STM32&#xff0c;所以我想其升级方案极有可能差不多。于是在…

基于SSM的智能仓储系统研究与设计

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

开源与闭源:大模型时代的技术交融与商业平衡

一、开源和闭源的优劣势比较 1.1 开源 优势&#xff1a; 1.技术共享与吸引人才&#xff1a; 开源促进了技术共享&#xff0c;吸引了全球范围内的人才参与大模型的发展&#xff0c;形成了庞大的开发者社区。 2.推动创新&#xff1a; 开源模式鼓励开发者共同参与&#xff0c;推动…

【STM32】RTC(实时时钟)

1.RTC简介 本质&#xff1a;计数器 RTC中断是外部中断&#xff08;EXTI&#xff09; 当VDD掉电的时候&#xff0c;Vbat可以通过电源--->实时计时 STM32的RTC外设&#xff08;Real Time Clock&#xff09;&#xff0c;实质是一个 掉电 后还继续运行的定时器。从定时器的角度…

腾讯云4核8G服务器性能如何多少钱一年?

腾讯云服务器4核8G配置优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云百科txybk.com分…

牛客——OR36 链表的回文结构(C语言,配图,快慢指针)

本题是没有对C的支持的&#xff0c;但因为Cpp支持C&#xff0c;所以这里就用C写了&#xff0c;可以面向更多用户 链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 思路一&#xff1a;链表翻转 简单的想想整形我们怎么比较&#xff0c;就是将整形A 依次取尾&#xff0c;放到整形…

航天联志Aisino-AISINO26081R服务器通过调BIOS用U盘重新做系统(windows系统通用)

产品名称:航天联志Aisino系列服务器 产品型号:AISINO26081R CPU架构&#xff1a;Intel 的CPU&#xff0c;所以支持Windows Server all 和Linux系统&#xff08;重装完系统可以用某60驱动管家更新所有硬件驱动&#xff09; 操作系统&#xff1a;本次我安装的服务器系统为Serv…

python趣味编程-5分钟实现一个Tic Tac Toe游戏(含源码、步骤讲解)

The Tic Tac Toe In Python是用 Python 编程语言编写的,这个Tic Tac Toe Game In Python是一个简单的基于 GUI 的策略游戏板,非常容易理解和使用。 所有的游戏规则都是一样的,就像我们玩实时井字棋一样,这是一个简单的多人游戏。 Python 中的 Tic Tac Toe 游戏:项目信息 …

物理驱动深度学习方法总结

一、物理驱动深度学习方法总结 现有博主更新物理驱动深度学方法总体介绍 二、 PINN介绍 PINN综述Blog介绍&#xff1a;内嵌物理知识神经网络 &#xff08;Physics Informed Neural Network&#xff0c;简称PINN&#xff09; 是一种科学机器在传统数值领域的应用方法&…

ping命令使用示例解析

【一】ping命令简介 ping &#xff08;Packet Internet Groper&#xff09;是一种因特网包探索器&#xff0c;用于测试网络连接量的程序。ping的一般用途有&#xff1a; ①【测试网络物理链路是否正常】&#xff1a;通过将ICMP(Internet控制消息协议)回显数据包发送到网络终端&…

[PHP]关联和操作MySQL数据库然后将数据库部署到ECS

在Mac电脑上使用VS Code进行PHP开发并关联操作MySQL数据库&#xff0c;然后将数据库部署到ECS。 1.安装PHP和MySQL 确保你的Mac上已经安装了PHP和MySQL。你可以使用Homebrew来安装它们&#xff1a; $ brew install php $ brew install mysql 安装mysql完成后记住这一句: …

蓝桥杯第三周算法竞赛D题E题

发现更多计算机知识&#xff0c;欢迎访问Cr不是铬的个人网站 D迷宫逃脱 拿到题目一眼应该就能看出是可以用动态规划来解决。但是怎么定义dp呢? 这个题增加难度的点就在当所在位置与下一个要去的位置互质的时候&#xff0c;会消耗一把钥匙。当没有钥匙的时候就不能移动了。想…

cocos----刚体

刚体&#xff08;Rigidbody&#xff09; 刚体&#xff08;Rigidbody&#xff09;是运动学&#xff08;Kinematic&#xff09;中的一个概念&#xff0c;指在运动中和受力作用后&#xff0c;形状和大小不变&#xff0c;而且内部各点的相对位置不变的物体。在 Unity3D 中&#xff…

使用 React Flow 构建一个思维导图应用

思维导图是围绕共同主题或问题将思想、概念、信息或任务分组的视觉表示。思维导图应用是一种软件应用&#xff0c;允许您创建、可视化和组织您的思想、想法和信息作为思维导图。本文将向您展示如何实现自己的思维导图应用程序。 在我们开始之前&#xff0c;我想向您展示一下我们…

ke11..--2其他界面也要提取我的locatStarage

获取浏览器里面的本地缓存 localStorage就是我们的浏览器缓存在哪都可以用 下面代码是获取打印到我们的页面上 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> …

Hessian协议详解

前言 Hessian协议是一种基于二进制的轻量级远程调用协议&#xff0c;用于在分布式系统中进行跨语言的通信。它使用简单的二进制格式来序列化和反序列化数据&#xff0c;并支持多种编程语言&#xff0c;如Java、C#、Python等。Hessian协议相对于其他协议的优势在于其简单性和高…