使用Feign出现空指针异常

说明:本文记录一次偶然出现的空指针异常,在微服务架构中,一个服务在调用另一个服务时,出现了空指针异常。

业务描述:在做订单超时功能时,大家都知道,可以使用RabbitMQ延迟队列,下单的同时给队列发送一个延迟消息(消息的内容是订单号),比如延迟10分钟。10分钟之后,该消息被消费者监听到,会根据该订单ID查询数据库,看该订单的状态是否为已支付,是则忽略,否则取消该订单,恢复商品库存等等其他操作,然而此时出现了空指针异常,消息未被消费,被路由到死信队列中。

(微服务调用报空指针异常)

在这里插入图片描述

(消息被路由到死信队列)

在这里插入图片描述

如下图的第三步:

在这里插入图片描述

分析

首先排除FeignClient的问题,因为下单减少库存,取消订单恢复库存,我使用的是同一个接口,只是修改了商品的正负数,不可能出现下单时可以,取消订单时再使用就报错。

(controller层代码)

    /*** 根据ID更新商品库存* @param id* @param num*/@PutMapping("/update/{id}/{num}")public void updateStockById(@PathVariable("id") Long id, @PathVariable("num") Integer num){itemService.updateStockById(id,num);}

(service层代码)

    @Overridepublic void updateStockById(Long id, Integer num) {if (!ObjectUtil.isAllNotEmpty(id, num)) {System.out.println("参数不能为空");}if (id < 0 || num < 0) {System.out.println("参数非法");}update().setSql("stock = stock + " + num).eq("id", id).update();}

其次,再思考会不会不是因为Feign的调用报错,而是微服务之间有什业务产生的报错。于是,我找到了拦截器

为了保证用户登录后,经过Gateway(网关)后,信息可以被下游服务获取到,我的代码中是使用MVC拦截器+Feign拦截器实现的,如下图:

在这里插入图片描述

每个服务会有两个拦截器,分别把服务接收到的请求,发出的请求拦截到,然后分别解析用户信息,添加用户信息到请求头,以此达到参数透传,用户信息可在微服务之间流传。

MVC拦截器代码(获取请求头中用户的ID,存到ThreadLocal中)

public class AuthorizationInterceptor implements HandlerInterceptor {/*** 收到请求会执行的方法* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String id = request.getHeader("authorization");if (id != null && id != ""){long l = Long.parseLong(id);TokenThreadLocal.set(l);}else {responseHandler(response);return false;}// 放行return true;}……
}

Feign拦截器(将本服务中的ThreadLocal中的用户ID再设置到请求头上)

/*** 发送请求拦截器*/
@Slf4j
public class AuthorizationRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {requestTemplate.header("authorization",TokenThreadLocal.get().toString());}
}

排查

给这两个地方分别打上断点,等订单超时后进入拦截器的代码,排查一下;

断点来到Feign拦截器,选中这行代码一看,原来是这里报了空指针异常

在这里插入图片描述

再一看,原来是TokenThreadLocal.get().toString()这里是空的;

在这里插入图片描述

然后恍然大悟,MQ发送消息是异步请求,ThreadLocal本地线程池对象,自然为空;

解决

很自然的想到一种很简单的解决方法,发送消息的时候把ThreadLocal中的值(用户ID)也给发到延迟队列中,然后在消费者监听的代码里面,再使用ThreadLocal的set()方法,把用户ID设置到线程池中;

把订单ID、用户ID封装成一个Map,转为json格式发送到延迟队列里;

在这里插入图片描述

消费者代码这边,使用ThreadLocal的set()方法,把用户ID再设置进去;

在这里插入图片描述

启动,测试下单,等待订单超时,清理超时订单,进入断点,问题解决!

在这里插入图片描述

总结

这是一个非常隐蔽的异常,因为设置了死信队列,未被成功消费的消息会被路由到死信队列中,程序并不会报错,并且因为订单表的内容大部分是在订单服务中,此异常仅仅会影响订单被取消后,调用商品服务恢复商品库存数量这一个很小的功能未能执行,要排除出来是非常困难的。

而问题原因,概括来说,是因为ThreadLocal的值不能在RabbitMQ的消息中传递,导致在使用拦截器获取ThreadLocal值的时候报了空指针异常

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

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

相关文章

数据结构—数组和广义表

4.2数组 数组&#xff1a;按一定格式排列起来的&#xff0c;具有相同类型的数据元素的集合。 **一维数组&#xff1a;**若线性表中的数据元素为非结果的简单元素&#xff0c;则称为一维数组。 **一维数组的逻辑结构&#xff1a;**线性结构&#xff0c;定长的线性表。 **声明…

TD1850多用表校准系统参考标准

参考标准 分类 标准名称 国家标准 GB/T 13978-2008 数字多用表 GB/T 15637-2012 数字多用表校准仪通用规范 计量法规 JJF 1075-2015 钳形电流表校准规范 JJF 1284-2011 交直流电表校验仪校准规范 JJF 1587-2016 数字多用表校准规范 JJG 124-2005 电流表、电压表、功率表及…

【多模态】18、ViLD | 通过对视觉和语言知识蒸馏来实现开集目标检测(ICLR2022)

文章目录 一、背景二、方法2.1 对新类别的定位 Localization2.2 使用 cropped regions 进行开放词汇检测2.3 ViLD 三、效果 论文&#xff1a;Open-vocabulary Object Detection via Vision and Language Knowledge Distillation 代码&#xff1a;https://github.com/tensorflo…

三子棋(超详解+完整码源)

三子棋 前言一&#xff0c;游戏规则二&#xff0c;所需文件三&#xff0c;创建菜单四&#xff0c;游戏核心内容实现1.棋盘初始化1.棋盘展示3.玩家下棋4.电脑下棋5.游戏胜负判断6.game&#xff08;&#xff09;函数内部具体实现 四&#xff0c;游戏运行实操 前言 C语言实现三子棋…

8.10 PowerBI系列之DAX函数专题-TopN中实现动态指标

需求 实现 建立一个辅助表供切片器选择 2 建立条件判断度量值top_measure swich(true(),selectedvalue(table[tope_type])"按数量top",sum(order_2[产品数量]),selectedvalue(table[tope_type])"按金额top",sum(order_2[订单金额]),selectedvalue(table…

aop实现方式及基本使用

aop实现方式 aspectj 编译器增强&#xff0c;直接修改源码可以不借助Spring实现 也没有用代理对象 &#xff08;ajc编译器&#xff09; aop 的原理并非代理一种, 编译器也能玩出花样&#xff08;直接修改源码&#xff09; 运行时需要在 VM options 里加入 -javaagent:D:/envir…

Matlab的SimuLink对FS32K144编程--内部数据存储Flash

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ 前言 Flah擦写是由寿命的&#xff0c;应当减免无效的擦写&#xff0c;如数据值不变不进行擦写 1、新建工程完成后&#xff0c;拖出Flash的存储控制初始化…

ROS 2 — 托管(生命周期)节点简介

一、说明 这篇文章是关于理解ROS 2中托管&#xff08;生命周期&#xff09;节点的概念。我们描述了概念性的想法以及我们为什么需要它。所以让我们开始吧&#xff01; 二、托管式节点 — 什么和为什么&#xff1f; 为了理解托管式节点&#xff0c;让我们从一个简单的问题陈述开…

串口通讯接口类型:TTL、RS232和RS485(电平标准)

串口通讯接口类型&#xff1a;TTL、RS232和RS485 在串口通信中&#xff0c;常用的接口类型包括TTL、RS-232和RS-485&#xff0c;TTL、RS-232、RS422、RS-485是指的电平标准(电信号)。 通信协议规定了数据传输的规则和格式&#xff0c;包括数据的起始位、停止位、数据位数、校…

内网穿透远程查看内网监控摄像头

内网穿透远程查看内网监控摄像头 在现代社会中&#xff0c;大家总是奔波于家和公司之间。大部分时间用于工作中&#xff0c;也就很难及时知晓家中的动态情况&#xff0c;对于家中有老人、小孩或宠物的&#xff08;甚至对居住环境安全不放心的&#xff09;&#xff0c;这已然是…

Retrospectives on the Embodied AI Workshop(嵌入式人工智能研讨会回顾) 论文阅读

论文信息 题目&#xff1a;Retrospectives on the Embodied AI Workshop 作者&#xff1a;Matt Deitke, Dhruv Batra, Yonatan Bisk 来源&#xff1a;arXiv 论文地址&#xff1a;https://arxiv.org/pdf/2210.06849 Abstract 我们的分析重点关注 CVPR Embodied AI Workshop 上…

JiaYu说:如何做好IT类的技术面试?

IT类的技术面试 面试IT公司的小技巧IT技术面试常见的问题嵌入式技术面试嵌入式技术面试常见的问题嵌入式软件/硬件面试题 JiaYu归属嵌入式行业&#xff0c;所以这里只是以普通程序员的角度去分析技术面试的技巧 当然&#xff0c;也对嵌入式技术面试做了小总结&#xff0c;友友们…

vite / nuxt3 项目使用define配置/自定义,可以使用process.env.xxx获取的环境变量

每日鸡汤&#xff1a;每个你想要学习的瞬间&#xff0c;都是未来的你向自己求救 首先可以看一下我的这篇文章了解一下关于 process.env 的环境变量。 对于vite项目&#xff0c;在我们初始化项目之后&#xff0c;在浏览器中打印 process.env&#xff0c;只有 NODE_ENV这个变量&…

【组内工作】木马回联

文章目录 C2服务器安装和运行方法CrossC2运行方法sliver运行方法empire安装方法DeimosC2安装教程TrevorC2安装教程&#xff1a; C2服务器的流量特征CrossC21. 心跳包2. 命令3. ja3/ja3s Sliver1. http2. https empirehttphttps DeimosC2https TrevorC2 C2服务器安装和运行方法 …

iperf3 编译安装及网讯WX1860千兆网口测试

iperf3 编译安装及网讯1860千兆网口测试 编译安装 安装包下载地址:https://github.com/esnet/iperf/archive/refs/tags/3.8.tar.gz 将安装包iperf-3.8.tar.gz拷贝测试系统盘桌面,使用如下命令进行编译安装: tar zxvf iperf-3.8.tar.gz cd iperf-3.8 ./configure make s…

HDFS基本操作命令

这里写目录标题 HDFS Shell CLI客户端说明常用命令hadoop fs -mkdir [-p] <path>hadoop fs -ls [-h] [-R] [<path>...]上传文件到指定目录下方法一:hadoop fs -put [-f] [-p] <localsrc>.....<dst>方法二&#xff1a;hadoop fs -moveFromLocal <loc…

Vue源码学习 - 异步更新队列 和 nextTick原理

目录 前言一、Vue异步更新队列二、nextTick 用法三、原理分析四、nextTick 源码解析1&#xff09;环境判断2&#xff09;nextTick() 五、补充 前言 在我们使用Vue的过程中&#xff0c;基本大部分的 watcher 更新都需要经过 异步更新 的处理。而 nextTick 则是异步更新的核心。…

MacOS本地安装Hadoop3

金翅大鹏盖世英&#xff0c;展翅金鹏盖世雄。 穿云燕子锡今鸽&#xff0c;踏雪无痕花云平。 ---------------- 本文密钥&#xff1a;338 ----------------- 本文描述了在macbook pro的macos上安装hadoop3的过程&#xff0c;也可以作为在任何类linux平台上安装hadoop3借鉴。 …

4、Linux驱动开发:设备-设备号设备号注册

目录 &#x1f345;点击这里查看所有博文 随着自己工作的进行&#xff0c;接触到的技术栈也越来越多。给我一个很直观的感受就是&#xff0c;某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了&#xff0c;只有经常会用到的东西才有可能真正记…

Verilog语法学习——LV2_异步复位的串联T触发器

LV2_异步复位的串联T触发器 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 题目描述&#xff1a; 用verilog实现两个串联的异步复位的T触发器的逻辑&#x…