当前位置: 首页 > news >正文

一次日志记录中使用fastjson涉及到ByteBuffer的教训

背景

目前本人在公司负责的模块中,有一个模块是负责数据同步的,主要是将我们数据产线使用的 AWS Dynamodb 同步的我们的测试QA 的环境的 MongoDB 的库中,去年开始也提供了使用 EMR 批量同步的功能,但是有时候业务也需要少量的数据进行同步测试,所以也通过了抽样数据同步的功能。

过程

本周的时候,LS项目研发的同事,和我反馈一个问题,主要是表现是发现同步到MongoDB库中的部分表的字段有问题,下游没法解析使用,随后我就开始排查代码
看下的这边同步的部分代码

/*** Synchronizes data by rewriting from source to sink database.** @param syncMessage The message model containing synchronization details.* @param source_db   The source DynamoDB client.* @param sink_db     The sink DynamoDB client.* @param parameters  Parameters for querying the source database.* @return The number of successful sync operations.*/private static int syncDataByRewrite(SyncPartDDBMessageModel syncMessage, AmazonDynamoDBClient source_db, AmazonDynamoDBClient sink_db, List<String> parameters) {int syncSuccessCount = 0;String table_name = syncMessage.getTable_name();List<Map<String, AttributeValue>> sync_items = new ArrayList<>();for (String parameter : parameters) {QueryResult queryResult = queryDataFromSource(source_db, syncMessage, parameter);if (queryResult != null && queryResult.getItems() != null && !queryResult.getItems().isEmpty()) {sync_items.addAll(queryResult.getItems());syncSuccessCount++;}}try {log.info("start sync data:" + JSON.toJSONString(sync_items));AWSDynamoDBUtils.batchWrite(sink_db, table_name, sync_items);} catch (Exception e) {log.error("Error syncing data for table {}: {}", table_name, e.getMessage(), e);}return syncSuccessCount;}

其实核心代码就如上面一样,咋一看,这段代码是没有问题的,因为之前我也对齐进行过测试,数据同步也是 OK 的,后来同事和我说 正常的字段都是 OK 的,但是 Binary 类型的字段存在问题,由于公司的之前使用的 Dynamodb的数据库,Dynamodb对每个 Item 的大小有限制,即512K,为了更多存储,减少不必要的 Chunk,我们将很多大的字段进行的 GZIP 压缩后用二进制的Binary 存储。

定位问题

当我听到是 Binary 类型的字段有问题的时候,第一反应是 想,是不是我们的 proxy 有问题,因为我这边使用的了写 Mongodb 适配Dynamodb 的 proxy, 后来问了组件的同事,说代码也已经很久没问题了,应该没问题的~
后来也是考虑是不是batchWrite的底层写得有问题,也是各种猜测去定位问题,浪费了很长时间
后来无意之前,我注释了下代码,仅仅 就注释了一行代码,你们猜是什么?
··
··
··
就是 log.info(“start sync data:” + JSON.toJSONString(sync_items));
对,我注释了一样记录日志的代码,居然程序没问题了这搞的我很尴尬哎呀

寻找问题的根源

最近也比较忙,当时定位到问题后,我想找找为什么会这样~
刚好今天周六有时间,我吧 FastJson 的源码来了来,我调试看下,我使用的版本是: fastjson2 git:(2.0.26)

测试

在实际我们的数据同步过程中,Map<String, AttributeValue> 里面的AttributeValue 是 Dynamodb返回的实体对象,是一个比较复杂的对象,我就不使用了,我这边只是测试了Buffer的

   @Testpublic void testBufferObjectToJsonString1() throws Exception {String drugId = "53b8acd8694f4ddabefc76b3a6d58976";ByteBuffer byteBuffer = compressString(drugId);System.out.println("byteBuffer:" + byteBuffer);System.out.println("drugIdJSONString:" + JSON.toJSONString(byteBuffer));System.out.println("byteBuffer2:" + byteBuffer);System.out.println("drugIdJSONString2:" + JSON.toJSONString(byteBuffer));}@Testpublic void testBufferObjectToJsonString2() throws Exception {String drugId = "53b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d58976";ByteBuffer byteBuffer = compressString(drugId);System.out.println("byteBuffer:" + byteBuffer);System.out.println("drugIdJSONString:" + JSON.toJSONString(byteBuffer));System.out.println("byteBuffer2:" + byteBuffer);System.out.println("drugIdJSONString2:" + JSON.toJSONString(byteBuffer));}

可以给大家看下 这2个测试方法的返回:
第一个测试的返回:

byteBuffer:java.nio.HeapByteBuffer[pos=0 lim=32 cap=32]
drugIdJSONString:{"char":"㔳","direct":false,"double":1.4039733842967137E165,"float":2.1439479E-7,"int":1684103781,"long":7377801321278300470,"readOnly":false,"short":25653}
byteBuffer2:java.nio.HeapByteBuffer[pos=28 lim=32 cap=32]com.alibaba.fastjson.JSONException: toJSONString errorat com.alibaba.fastjson.JSON.toJSONString(JSON.java:1477)at com.patsnap.data.process.platform.job.syncPartDDB.SyncPartDDBJobTest.testBufferObjectToJsonString1(SyncPartDDBJobTest.java:143)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at junit.framework.TestCase.runTest(TestCase.java:176)at junit.framework.TestCase.runBare(TestCase.java:141)at junit.framework.TestResult$1.protect(TestResult.java:122)at junit.framework.TestResult.runProtected(TestResult.java:142)at junit.framework.TestResult.run(TestResult.java:125)at junit.framework.TestCase.run(TestCase.java:129)at junit.framework.TestSuite.runTest(TestSuite.java:252)at junit.framework.TestSuite.run(TestSuite.java:247)at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: java.nio.BufferUnderflowExceptionat java.nio.Buffer.nextGetIndex(Buffer.java:510)at java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)at com.alibaba.fastjson2.writer.FieldWriterDoubleValueFunc.write(FieldWriterDoubleValueFunc.java:44)at com.alibaba.fastjson2.writer.ObjectWriter8.write(ObjectWriter8.java:97)at com.alibaba.fastjson.JSON.toJSONString(JSON.java:1469)... 21 more

第二个测试的返回:

byteBuffer:java.nio.HeapByteBuffer[pos=0 lim=96 cap=96]
drugIdJSONString:{"char":"㔳","direct":false,"double":1.4039733842967137E165,"float":2.1439479E-7,"int":1684103781,"long":7377801321278300470,"readOnly":false,"short":25653}
byteBuffer2:java.nio.HeapByteBuffer[pos=28 lim=96 cap=96]
drugIdJSONString2:{"char":"㠹","direct":false,"double":9.958328793464587E-43,"float":1.3592432E22,"int":879113316,"long":7233170664182724406,"readOnly":false,"short":25139}

第一个测试居然报错了,从报错的堆栈上看,java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)这个异常了
第二个测试没有报错,但是存在问题,就是明显2个对象不一样了,我们从第二个HeapByteBuffer的position的值可以看到,他的值偏移了,说明了什么 ,说明了 FastJosn 读取了ByteBuffer的内容,但是没有做buffer rewind重置位置的操作,这也太坑了

查看源码

static String toJSONString(Object object) {
JSONWriter.Context writeContext = new JSONWriter.Context(JSONFactory.defaultObjectWriterProvider);boolean pretty = (writeContext.features & JSONWriter.Feature.PrettyFormat.mask) != 0;JSONWriter jsonWriter;
if (JVM_VERSION == 8) {jsonWriter = new JSONWriterUTF16JDK8(writeContext);
} else if ((writeContext.features & JSONWriter.Feature.OptimizedForAscii.mask) != 0) {....
} else {....
}try (JSONWriter writer = pretty ?new JSONWriterPretty(jsonWriter) : jsonWriter) {if (object == null) {writer.writeNull();} else {writer.rootObject = object;writer.path = JSONWriter.Path.ROOT;Class<?> valueClass = object.getClass();if (valueClass == JSONObject.class) {writer.write((JSONObject) object);} else {JSONWriter.Context context = writer.context;boolean fieldBased = (context.features & JSONWriter.Feature.FieldBased.mask) != 0;ObjectWriter<?> objectWriter = context.provider.getObjectWriter(valueClass, valueClass, fieldBased);objectWriter.write(writer, object, null, null, 0);}}return writer.toString();
} catch (NullPointerException | NumberFormatException e) {throw new JSONException("JSON#toJSONString cannot serialize '" + object + "'", e);
}
}

上面的toJSONString的部分代码的截取,主要是看 objectWriter.write(writer, object, null, null, 0);这个地方的实现,最终我调试发现调用了com.alibaba.fastjson2.writer.ObjectWriter8 里面的 write方法

 @Overridepublic void write(JSONWriter jsonWriter, Object object, Object fieldName, Type fieldType, long features) {long featuresAll = features | this.features | jsonWriter.getFeatures();boolean beanToArray = (featuresAll & BeanToArray.mask) != 0;if (jsonWriter.jsonb) {if (beanToArray) {writeArrayMappingJSONB(jsonWriter, object, fieldName, fieldType, features);return;}writeJSONB(jsonWriter, object, fieldName, fieldType, features);return;}if (beanToArray) {writeArrayMapping(jsonWriter, object, fieldName, fieldType, features | this.features);return;}if (!serializable) {if ((featuresAll & JSONWriter.Feature.ErrorOnNoneSerializable.mask) != 0) {errorOnNoneSerializable();return;}if ((featuresAll & JSONWriter.Feature.IgnoreNoneSerializable.mask) != 0) {jsonWriter.writeNull();return;}}if (hasFilter(jsonWriter)) {writeWithFilter(jsonWriter, object, fieldName, fieldType, 0);return;}jsonWriter.startObject();if (((features | this.features) & WriteClassName.mask) != 0 || jsonWriter.isWriteTypeInfo(object, features)) {writeTypeInfo(jsonWriter);}fieldWriter0.write(jsonWriter, object);fieldWriter1.write(jsonWriter, object);fieldWriter2.write(jsonWriter, object);fieldWriter3.write(jsonWriter, object);fieldWriter4.write(jsonWriter, object);fieldWriter5.write(jsonWriter, object);fieldWriter6.write(jsonWriter, object);fieldWriter7.write(jsonWriter, object);jsonWriter.endObject();}

最终代码是执行了fieldWriter0到fieldWriter7的8个方式,这也解释了 我们的为什么我们打印的 Bytebuffer类型是这样的:

{"char":"㔳","direct":false,"double":1.4039733842967137E165,"float":2.1439479E-7,"int":1684103781,"long":7377801321278300470,"readOnly":false,"short":25653
}

image.png
这边也是刚好8个方式加起来读取了28
这边也同能解释了我第一个测试方式为什么会报错,再回头看下我第一个的 buffer 对象byteBuffer:java.nio.HeapByteBuffer[pos=0 lim=32 cap=32]
byteBuffer2:java.nio.HeapByteBuffer[pos=28 lim=32 cap=32]
为什么第二次 toJSONString 的错误就是因为,读取的位置不够了~所以在第一个测试在at java.nio.HeapByteBuffer.getDouble(HeapByteBuffer.java:531)的位置发送了错误,也应对了上面的源码的逻辑

解决方法

如果是的执行方法在使用toJSONString之前的,那是没有问题的,正常我们读取 buffer 完成后的,会重置位置,或者使用一个输出流去接收,然后再去读取,也是没有问题的,或者使用 ByteBuffer wrap = ByteBuffer.wrap(byteBuffer.array()); 也是没有问题的
当然你如果想要解决这个toJSONString的错误,也是可以的,正常我们都会将二进制使用 base64来表示的,这样就不存在问题,
上代码:

public class ByteBufferValueFilter implements ValueFilter {@Overridepublic Object process(Object object, String name, Object value) {if (value instanceof ByteBuffer) {ByteBuffer buffer = (ByteBuffer) value;byte[] bytes = new byte[buffer.remaining()];buffer.get(bytes); // 读取剩余的字节buffer.rewind(); // 重置 position 到起始位置return Base64.getEncoder().encodeToString(bytes);}return value;}
}

是可以解决的

后续

这个问题其实我在官方的issues也找到了这个问题:https://github.com/alibaba/fastjson/issues/2357
image.png

image.png

下面的回复是已经解决了这个问题的,但是我使用的2.0.26 居然还有这个问题,
我就顺便测试了1.2.83版本,这个也是2.0.26版本引用之前1.X的fastjson 的版本,
image.png

 @Test
public void testBufferObjectToJsonString2() throws Exception {String drugId = "53b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d5897653b8acd8694f4ddabefc76b3a6d58976";ByteBuffer byteBuffer = compressString(drugId);System.out.println("byteBuffer:" + byteBuffer);System.out.println("drugIdJSONString:" + com.alibaba.fastjson.JSON.toJSONString(byteBuffer));System.out.println("byteBuffer2:" + byteBuffer);System.out.println("drugIdJSONString2:" + JSON.toJSONString(byteBuffer));
}

输出:

byteBuffer:java.nio.HeapByteBuffer[pos=0 lim=96 cap=96]
drugIdJSONString:{"array":"NTNiOGFjZDg2OTRmNGRkYWJlZmM3NmIzYTZkNTg5NzY1M2I4YWNkODY5NGY0ZGRhYmVmYzc2YjNhNmQ1ODk3NjUzYjhhY2Q4Njk0ZjRkZGFiZWZjNzZiM2E2ZDU4OTc2","limit":96,"position":0}
byteBuffer2:java.nio.HeapByteBuffer[pos=0 lim=96 cap=96]
drugIdJSONString2:{"char":"㔳","direct":false,"double":1.4039733842967137E165,"float":2.1439479E-7,"int":1684103781,"long":7377801321278300470,"readOnly":false,"short":25653}

可以看到 在之前的做法也是将二进制去 base64表示的,不知道为什么在2.0.26 还会出现上面的问题
那我就顺便去官方 提一个issues吧,https://github.com/alibaba/fastjson2/issues/2877
后面看下是否会修复这个问题

总结

回顾上面,其实最大的一个问题就是,在记录日志的时候,不应该添加在代码执行逻辑之前,这是一个不好的代码习惯,应该将日志记录放在代码执行逻辑之后。此外,代码的测试用例要做全,排查代码的时候,定位问题的时候 更加敏锐些。

相关文章:

一次日志记录中使用fastjson涉及到ByteBuffer的教训

背景 目前本人在公司负责的模块中&#xff0c;有一个模块是负责数据同步的&#xff0c;主要是将我们数据产线使用的 AWS Dynamodb 同步的我们的测试QA 的环境的 MongoDB 的库中&#xff0c;去年开始也提供了使用 EMR 批量同步的功能&#xff0c;但是有时候业务也需要少量的数据…...

掌握TCP连接管理与流量控制:从零开始

文章目录 1. TCP连接管理1.1 三次握手&#xff08;Three-way Handshake&#xff09;1.2 四次挥手&#xff08;Four-way Handshake&#xff09;1.3 TCP连接管理的重要性 2. TCP流量控制2.1 滑动窗口&#xff08;Sliding Window&#xff09;2.2 拥塞控制&#xff08;Congestion C…...

python提取b站视频的音频(提供源码

如果我想开一家咖啡厅&#xff0c;那么咖啡厅的音乐可得精挑细选&#xff01;又假设我非常喜欢o叔&#xff0c;而o叔只在b站弹钢琴&#xff0c;那这时候我就得想方设法把b站的视频转为音频咯&#xff01; 一、首先打开网页版bilibili&#xff0c;按F12&#xff1a; 二、刷新页面…...

嵌入式Linux ,QT5 鼠标键盘设备参数指定环境变量的方法

根文件系统中&#xff0c;一般用mdev来管理设备&#xff0c;不像udev方便&#xff0c;有时候在执行rcS脚本的时候因为&#xff0c;太快&#xff0c;有些设备比如鼠标还没在/dev/input中生成设备文件&#xff0c;最好使用前用mdev -s扫描并等待几秒钟&#xff0c;然后就可以在in…...

C语言钥匙迷宫2.0

目录 开头程序程序的流程图程序游玩的效果结尾 开头 大家好&#xff0c;我叫这是我58。废话不多说&#xff0c;咱们直接开始。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> #include <Windows.h> enum color {Y,B,R …...

【多线程】初步认识Thread类及其应用

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;多线程 / javaEE初阶 上篇文章我们简单介绍了什么是进程与线程&#xff0c;以及他们之间的区别与联系&#xff0c;实际应用中还是以多线程编程为主的&#xff0c;所以这篇文章就让我们更加深入地去剖…...

algorithm算法库学习之——划分操作和排序操作

algorithm此头文件是算法库的一部分。本篇介绍划分操作和排序操作。 划分操作 is_partitioned (C11) 判断范围是否已按给定的谓词划分 (函数模板) partition 将范围中的元素分为两组 (函数模板) partition_copy (C11) 复制一个范围&#xff0c;将各元素分为两组 (函数模板) st…...

XSS实验记录

目录 XXS地址 实验过程 Ma Spaghet Jeff Ugandan Knuckles Ricardo Milos Ah Thats Hawt Ligma Mafia Ok, Boomer XXS地址 XSS Game - Learning XSS Made Simple! | Created by PwnFunction 实验过程 Ma Spaghet 要求我们弹出一个alert(1337)sandbox.pwnfuncti…...

Cortex-A7的GIC(全局中断控制器)使用方法(7):基于stm32MP135的GIC配置中断效果测试

0 参考资料 STM32MP13xx参考手册.pdf&#xff08;RM0475&#xff09; ARM Generic Interrupt Controller Architecture version 2.0 - Architecture Specification.pdf 1 GIC配置中断效果测试 前面我们已经实现了GIC的配置&#xff0c;为了验证GIC是否配置有效&#xff0c;本例…...

c++动态数组new和delete

文章目录 动态数组的使用大全1. **基本创建和初始化**2. **动态调整大小**3. **动态数组的使用与标准库 std::vector**4. **动态数组作为函数参数**输出 5. **使用动态数组存储用户输入** 动态数组的使用大全 1. 基本创建和初始化 示例&#xff1a; #include <iostream&g…...

Redis热点知识速览(redis的数据结构、高性能、持久化、主从复制、集群、缓存淘汰策略、事务、Pub/Sub、锁机制、常见问题等)

Redis是一个开源的、使用内存作为存储的、支持数据结构丰富的NoSQL数据库。它的高性能、灵活性和简单易用使其在许多场景下成为首选的缓存解决方案。以下是Redis的常见和热点知识总结。 数据结构 Redis支持五种基本数据结构&#xff1a; String&#xff1a;字符串是Redis中最…...

【C++浅析】lambda表达式:基本结构 使用示例

基本结构 [捕获列表](参数列表) -> 返回类型 { // 函数体 } 捕获列表 ([ ]): 用于指定外部变量的捕获方式。可以&#xff1a; 通过值捕获&#xff1a;[x]通过引用捕获&#xff1a;[&x]捕获所有变量通过值&#xff1a;[]捕获所有变量通过引用&#xff1a;[&]自…...

利用Redis获取权限的多种方式

更多实战内容&#xff0c;可前往无问社区查看http://www.wwlib.cn/index.php/artread/artid/10333.html Redis是我们在实战中经常接触到的一款数据库&#xff0c;因其在前期打点中被利用后可直接影响服务器安全所以在攻防过程中也备受红队关注&#xff0c;在本文中会重点分享一…...

LeetCode - LCR 146- 螺旋遍历二维数组

LCR 146题 题目描述&#xff1a; 给定一个二维数组 array&#xff0c;请返回「螺旋遍历」该数组的结果。 螺旋遍历&#xff1a;从左上角开始&#xff0c;按照 向右、向下、向左、向上 的顺序 依次 提取元素&#xff0c;然后再进入内部一层重复相同的步骤&#xff0c;直到提取完…...

如何获取Bing站长工具API密钥

Bing站长工具近期悄然上线了网站URL推送功能&#xff0c;似乎有意跟随百度的步伐。这个新功能允许站长通过API向Bing提交链接数据&#xff0c;当然也可以通过Bing站长工具手动提交。 本文将详细介绍如何通过Bing站长工具生成用于网站链接推送的API密钥。 首先&#xff0c;访问…...

NC 调整数组顺序使奇数位于偶数前面(一)

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 输入一个长度…...

Unity异步把图片数据从显存下载到内存(GPU->CPU)

Unity异步把图片数据从显存下载到内存&#xff08;GPU->CPU&#xff09; 1.c#核心代码 using System.Collections; using System.Collections.Generic; using Unity.Collections; using UnityEditor.PackageManager.Requests; using UnityEngine; using UnityEngine.Rende…...

【MySQL】C/C++连接MySQL客户端,MySQL函数接口认知,图形化界面进行连接

【MySQL】C/C引入MySQL客户端 安装mysqlclient库mysql接口介绍初始化mysql_init链接数据库mysql_real_connect下发mysql命令mysql_query获取出错信息mysql_error获取执行结果mysql_store_result获取结果行数mysql_num_rows获取结果列数mysql_num_fields判断结果列数mysql_field…...

Wireshark分析工具

简单用例 首先打开软件&#xff0c;左上角点文件&#xff0c;选中要分析的文件列表。 导入用tcpdump抓的包后进行分析&#xff0c;这里要输入过滤条件&#xff0c;对网络包进行一定的过滤处理。&#xff08;这里172网段是阿里云的地址&#xff0c;用自己写的python2脚本对阿里…...

linux网络配置脚本

通过脚本&#xff0c;设置静态ip以及主机名 因为企业9的网络配置文件和企业7的不一样所以&#xff0c;我们以rhel9和rhel7为例 rhel7/centos7/openeuler #!/bin/bash cat > /etc/sysconfig/network-scripts/ifcfg-$1 << EOF DEVICE$1 ONBOOTyes BOOTPROTOnone IPAD…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...