fastjson序列化MessageExt对象问题(1.2.78之前版本)

前言

  无论是kafka,还是RocketMq,消费者方法参数中的MessageExt对象不能被 fastjson默认的方式序列化。

一、查看代码

@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,ConsumeConcurrentlyContext context) {try {GiftSendMessage message = JSON.parseObject(msgs.get(0).getBody(),GiftSendMessage.class);UserInfo userInfo = new UserInfo();userInfo.setMemberId(String.valueOf(message.getFromId()));userInfo.setScId(message.getScId());userInfo.setAnchorScid(message.getAnchorScid());userInfo.setAnchorId(message.getAnchorId());userInfo.setGiftSendToId(message.getToId());DrawByGiftSendConfig draw =filter.getGiftIdBySend().get(String.valueOf(message.getGiftId()));GiftSendRequest request = new GiftSendRequest();request.setActivityId(draw.getActivityId());request.setBoxType(draw.getBoxType());request.setGiftOrderId(message.getGiftOrderId());request.setBatch(message.getAmount());request.setSendTime(message.getSendTime());request.setUserInfo(userInfo);request.setPaymentVersion(PAYMENT_VERSION);this.userDrawService.giftSend(request);LOG.info("DRAW BY GIFT SEND WITH SANTA CHECKOUT, MQ-MESSAGE={}, REQUEST={}",JSON.toJSONString(message),JSON.toJSONString(request));} catch (Exception e) {LOG.error("GIFT-SEND-QUEUE CONSUME FATAL ERROR ON PARSING, DROPPED, MSG={},EXCEPTION={}, EXCEPTION-MESSAGE={}",JSON.toJSONString(msgs), e.getClass().getSimpleName(),e.getMessage(), e);} return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}

二、问题代码

在这里插入图片描述

三、原因分析

  上图中红色方框当中,用的序列化方式为 fastjson,此行代码会抛出异常,导致消费失败,进入重试队列,且没有任何业务日志输出。MQ源码如下:
在这里插入图片描述
如果异常,返回 ConsumeConcurrentlyStatus.RECONSUME_LATER;

结论:无论是kafka,还是RocketMq,消费者方法参数中的MessageExt对象不能被 fastjson默认的方式序列化。

环境:项目采用1.2.31 (最新版本1.2.78)
接下来,我们分析下fastjson序列化的完整过程:
fastjson反序列化的方式默认为采用 get方法、is方法作为序列化属性 字段的,序列化流程如下:
在这里插入图片描述
其中:在获取对象序列化的时候,MessageExt中有返回 ByteBuffer的get方法,代码如下:

public ByteBuffer getStoreHostBytes() {return socketAddress2ByteBuffer(this.storeHost);
} 
//socketAddress2ByteBuffer
public static ByteBuffer socketAddress2ByteBuffer(SocketAddress socketAddress) {ByteBuffer byteBuffer = ByteBuffer.allocate(8);return socketAddress2ByteBuffer(socketAddress, byteBuffer);
}
//socketAddress2ByteBuffer
public static ByteBuffer socketAddress2ByteBuffer(SocketAddress socketAddress, ByteBuffer
byteBuffer) {InetSocketAddress inetSocketAddress = (InetSocketAddress)socketAddress;byteBuffer.put(inetSocketAddress.getAddress().getAddress(), 0, 4);byteBuffer.putInt(inetSocketAddress.getPort());byteBuffer.flip();return byteBuffer;
}

Mq消息在接收到消息时,构造了返回了ByteBuffer对象的方法,该方法是nio中设计用于保存数据到缓冲区的目的。

3.1 ByteBuffer主要的属性,与fastjson的get方法反序列化方式

  • position: 其实是指从buffer读取或写入buffer的下一个元素位置。比如,已经写入buffer 3个元素那那么position就是指向第4个位置,即position设置为3(数组从0开始计);
  • limit:还有多少数据需要从buffer中取出,或还有多少空间可以放入;postition总是<=limit;
  • capacity: 表示buffer本身底层数组的容量。limit绝不能>capacity;

数据结构如下:
在这里插入图片描述

  • get()方法,一字节一字节读;
  • getChar()、getShort()、getInt()、getFloat()、getLong()、getDouble()读取相应字节数的数据;

3.2 最终原因分析得到

  至此:问题显而易见,fastjson在1.2.31及之前,没有提供ByteBuffer 序列化器,所以用了默认的javabean序列化器,而默认的javabean序列化器,又通过get方法反序列化,当遇见ByteBuffer时,ByteBuffer中会先遇到如下方法,getLong():

public long getLong() {return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
} //nextGetIndex
final int nextGetIndex(int nb) { // package-privateif (limit - position < nb)throw new BufferUnderflowException();int p = position;position += nb;return p;
}

每次读取position偏移8个字节,而MessageExt中,构建的ByteBuffer存储的时4个字节,所以会报错,完整的堆栈如下:
在这里插入图片描述

四、总结

  1. fastjson 序列化需注意问题,不能序列化RocketMq工具类中MessageExt对象,会报错;
  2. 原因:MessageExt包含ByteBuffer类型的nio包对象,而低版本fastjson没有该类型序列化器(JavaBeanSerializer),使用默认的序列化器;
  3. ByteBuffer中getLong方法,getLong方法的position偏移8个字节,而MessageExt中,构建的ByteBuffer存储的时4个字节,所以会BufferUnderflowException异常。
  4. BufferUnderflowException异常:表示在读取缓冲区时发生了下溢(underflow)的情况。下溢是指尝试从缓冲区中读取比可用数据量更多的数据;
  5. 无论是kafka,还是RocketMq,消费者方法参数中的MessageExt对象不能被 fastjson默
    认的方式序列化;

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

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

相关文章

江科大stm32学习笔记——【4-1】OLED

一.原理 1.调试方式 串口调试&#xff1a;通过串口通信&#xff0c;将调试信息发送到电脑端&#xff0c;电脑使用串口助手显示调试信息。 显示屏调试&#xff1a;直接将显示屏连接到单片机&#xff0c;将调试信息打印在显示屏上。 Keil调试模式&#xff1a;借助Keil软件的调…

resilience4j 2.0.0版本使用要求最低JDK17(使用踩坑记录)

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容&#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作…

六自由度Stewart平台的matlab模拟与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1运动学原理 4.2 Stewart平台运动学方程 5.完整工程文件 1.课题概述 六自由度Stewart平台的matlab模拟与仿真&#xff0c;模拟六自由度Stewart平台的动态变化情况以及伺服角度。 2.系统仿真结果 3.核…

v-rep--websocket接口

websocket是什么 V-REP 中的 Web Socket 是一种用于在 V-REP 和外部应用程序之间进行通信的协议和技术。Web Socket 基于 TCP 连接&#xff0c;可以提供双向、实时的数据传输&#xff0c;适用于互动性或实时交互性应用。 (比如v-rep在云服务器上运行&#xff0c;通过websocke…

【国产MCU】-CH32V307-定时器同步模式

定时器同步模式 文章目录 定时器同步模式1、定时器同步模式介绍2、驱动API介绍3、定时器同步模式实例1、定时器同步模式介绍 CH32V307的定时器能够输出时钟脉冲(TRGO),也能接收其他定时器的输入(ITRx)。不同的定时器的ITRx的来源(别的定时器的TRGO)是不一样的。 通用定…

Covalent Network的长期数据可用性 获得了众多加密 KOL的肯定及支持

随着 Web3 生态系统的动态发展&#xff0c;Covalent Network&#xff08;CQT&#xff09;的关键性正在显现&#xff0c;通过提供分布式、加密安全的数据层&#xff0c;以解决长期数据可用性的问题。Covalent Network&#xff08;CQT&#xff09;不仅仅是一个工具&#xff0c;更…

企业内部文件资料如何进行加密 ——防止泄露?

企业内部文件资料的加密是防止数据泄露的关键措施之一。 www.weaem.com 以下是一些建议&#xff0c;用于在企业内部进行文件资料的加密&#xff0c;以防止数据泄露&#xff1a; 选择适合的加密技术&#xff1a; 透明加密&#xff1a;这种加密方式允许用户在不改变原有操作习惯的…

简单网站模板1(HTML)

想要拥有自己的网站&#xff0c;却不知该如何才能简约好看&#xff0c;接下来分享一种自己搭建的网站模板&#xff0c;希望大家喜欢。 展示图&#xff1a; CODE: <!DOCTYPE html> <html> <head><title>我的网站</title><style>body {fo…

eltable 合计行添加tooltip

eltable 合计行添加tooltip 问题描述&#xff1a; eltable 合计行单元格内容过长会换行&#xff0c;需求要求合计行数据超长显示 … &#xff0c;鼠标 hover 时显示提示信息。 解决方案&#xff1a;eltable合计行没有对外的修改接口&#xff0c;想法是 自己实现一个tooltip&a…

JVM对象创建与内存分配机制

JVM对象创建与内存分配机制 JVM对象创建与内存分配机制 JVM对象创建与内存分配机制对象的创建过程内存分配对象栈上分配对象逃逸分析标量替换 对象在Eden区分配大对象直接进入老年代长期存活的对象将进入老年代对象年龄动态判断老年代空间分配担保机制 对象头与指针压缩对象头利…

课时49:表达式_表达式进阶_集合基础

3.3.2 集合基础 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习。 基础知识 简介 所谓的集合&#xff0c;主要是针对多个条件表达式组合后的结果&#xff0c;尤其是针对于逻辑场景的组合。初中数学的相关逻辑示意图&#xff1a;表现样式 两个…

将四个主页面配置为 tab-bar 的子路由

使用vant组件库 路由 {path: /, name: layout,component: () > import(/views/layout),children: [{path: , // 默认子路由name: home,component: () > import(/views/home)},{path: qa,name: qa,component: () > import(/views/qa)},{path: video,name: video,compo…

阿里云2核4G服务器租用价格85元一年,30元3个月

阿里云2核4G服务器多少钱一年&#xff1f;2核4G服务器1个月费用多少&#xff1f;2核4G服务器30元3个月、85元一年&#xff0c;轻量应用服务器2核4G4M带宽165元一年&#xff0c;本文阿里云服务器网整理的2核4G参加活动的主机是ECS经济型e实例和u1云服务器&#xff0c;阿里云服务…

图搜索基础-深度优先搜索

图搜索基础-深度优先搜索 参考原理引入流程解析手推例子 代码实现运行结果结果分析 参考 理论参考&#xff1a;深蓝学院 实现参考&#xff1a;github项目 原理 引入 对于这样一个图&#xff0c;我们试图找到S到G的通路&#xff1a; 计算机程序不会像人眼一样&#xff0c;一…

如何做代币分析:以 USDT 币为例

作者&#xff1a;lesleyfootprint.network 编译&#xff1a;cicifootprint.network 数据源&#xff1a;USDT Token Dashboard &#xff08;仅包括以太坊数据&#xff09; 在加密货币和数字资产领域&#xff0c;代币分析起着至关重要的作用。代币分析指的是深入研究与代币相关…

DolphinScheduler——工作流实例的生命周期

目录 一、DolphinScheduler架构原理 1.1 系统架构图 1.2 DolphinScheduler核心概念 1.2 创建工作流 1.2.1 如何触发一个工作流实例 1.2.2 任务调度链路监控 1.2.3 Workflow-DAG解析 DAG解析 Dispatch分发流程 Master和Worker的交互过程 1.3 任务运行状态 该篇文章主…

Leetcode : 215. 数组中的第 K 个最大元素

给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 思路&#xff1a;最开始排序算法&…

MySQL 存储过程批量插入总结

功能需求背景&#xff1a;今天接到产品经理核心业务表的数据压测功能&#xff0c;让我向核心业务表插入百万级的业务量数据&#xff0c;我首先想到的办法就是存储过程实现数据的批量 。 由于无法提供核心业务表&#xff0c;本文仅仅提供我刚刚自己创建的表bds_base_user 表做相…

nginx 反向代理 与缓存功能

一 理论说明 &#xff08;一&#xff09;反向代理简介 反向代理&#xff1a;reverse proxy&#xff0c;指的是代理外网用户的请求到内部的指定的服务器&#xff0c;并将数据返回给用户的一种方式&#xff0c;这是用的比较多的一种方式。 即 代理服务机 Nginx 除了可以在企…

算法——滑动窗口之最大连续1的个数、将x减到0的最小操作数、水果成篮

3.最大连续1的个数 题目:. - 力扣&#xff08;LeetCode&#xff09; 题目要求的是给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 按照题目正面去做,还要替换0,很麻烦 反正我们最后要求的是最长…