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

Apache Beanutils为什么被禁止使用?

收录于热门专栏Java基础教程系列(进阶篇)

在实际的项目开发中,对象间赋值普遍存在,随着双十一、秒杀等电商过程愈加复杂,数据量也在不断攀升,效率问题,浮出水面。

问:如果是你来写对象间赋值的代码,你会怎么做?
答:想都不用想,直接代码走起来,get、set即可。

问:下图这样?

在这里插入图片描述

答:对啊,你怎么能把我的代码放到网上?

问:没,我只是举个例子

答:这涉及到商业机密,是很严重的问题

问:我发现你挺能扯皮啊,直接回答问题行吗?

答:OK,OK,我也觉得这样写很low,上次这么写之后,差点挨打
对象太多,ctrl c + strl v,键盘差点没敲坏;
而且很容易出错,一不留神,属性没对应上,赋错值了;
代码看起来很傻缺,一个类好几千行,全是get、set复制,还起个了自以为很优雅的名字transfer;
如果属性名不能见名知意,还得加上每个属性的含义注释(基本这种赋值操作,都是要加的,注释很重要,注释很重要,注释很重要);
代码维护起来很麻烦;
如果对象过多,会产生类爆炸问题,如果属性过多,会严重违背阿里巴巴代码规约(一个方法的实际代码最多20行);
问:行了,行了,说说,怎么解决吧。

答:很简单啊,可以通过工具类Beanutils直接赋值啊

问:我听说工具类最近很卷,你用的哪个啊?
答:就Apache自带的那个啊,贼简单。我手写一个,给你欣赏一下。
在这里插入图片描述
问:你这代码报错啊,避免用Apache Beanutils进行属性的copy。

答:没报错,只是严重警告而已,代码能跑就行,有问题再优化呗

问:你这什么态度?人事在哪划拉的人,为啥会出现严重警告?
答:拿多少钱,干多少活,我又不是XXX,应该是性能问题吧

问:具体什么原因导致的呢?

答:3000块钱还得手撕一下 apache copyProperties的源代码呗?

通过单例模式调用copyProperties,但是,每一个方法对应一个BeanUtilsBean.getInstance()实例,每一个类实例对应一个实例,这不算一个真正的单例模式。

public static void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {BeanUtilsBean.getInstance().copyProperties(dest, orig);
}

性能瓶颈 --> 日志太多也是病
通过源码可以看到,每一个copyProperties都要进行多次类型检查,还要打印日志。

/*** org.apache.commons.beanutils.BeanUtils.copyProperties方法源码解析*/
public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {// 类型检查if (dest == null) {throw new IllegalArgumentException("No destination bean specified");} else if (orig == null) {throw new IllegalArgumentException("No origin bean specified");} else {// 打印日志if (this.log.isDebugEnabled()) {this.log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + ")");}int var5;int var6;String name;Object value;// 类型检查// DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能if (orig instanceof DynaBean) {// 获取源对象所有属性DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();DynaProperty[] var4 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {DynaProperty origDescriptor = var4[var6];// 获取源对象属性名name = origDescriptor.getName();// 判断源对象是否可读、判断目标对象是否可写if (this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {// 获取对应的值value = ((DynaBean)orig).get(name);// 每个属性都调用一次copyPropertythis.copyProperty(dest, name, value);}}} else if (orig instanceof Map) {Map<String, Object> propMap = (Map)orig;Iterator var13 = propMap.entrySet().iterator();while(var13.hasNext()) {Map.Entry<String, Object> entry = (Map.Entry)var13.next();String name = (String)entry.getKey();if (this.getPropertyUtils().isWriteable(dest, name)) {this.copyProperty(dest, name, entry.getValue());}}} else {PropertyDescriptor[] origDescriptors = this.getPropertyUtils().getPropertyDescriptors(orig);PropertyDescriptor[] var14 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {PropertyDescriptor origDescriptor = var14[var6];name = origDescriptor.getName();if (!"class".equals(name) && this.getPropertyUtils().isReadable(orig, name) && this.getPropertyUtils().isWriteable(dest, name)) {try {value = this.getPropertyUtils().getSimpleProperty(orig, name);this.copyProperty(dest, name, value);} catch (NoSuchMethodException var10) {}}}}}
}

通过 jvisualvm.exe 检测代码性能
再通过jvisualvm.exe检测一下运行情况,果然,logging.log4j赫然在列,稳居耗时Top1。

问:还有其它好的方式吗?性能好一点的
答:当然有,据我了解有 4 种工具类,实际上,可能会有更多,话不多说,先简单介绍一下。
org.apache.commons.beanutils.BeanUtils;
org.apache.commons.beanutils.PropertyUtils;
org.springframework.cglib.beans.BeanCopier;
org.springframework.beans.BeanUtils;
问:那你怎么不用?
答:OK,我来演示一下

public class Test {public static void main(String[] args) {User user = new User();user.setUserId("1");user.setUserName("测试编程");user.setCardId("123");user.setCreateTime("2023-01-03");user.setEmail("666666666@qq.com");user.setOperate("测试");user.setOrgId("46987916");user.setPassword("123456");user.setPhone("10086");user.setRemark("456");user.setSex(1);user.setStatus("1");user.setTel("110");user.setType("0");user.setUpdateTime("2023-01-05");User target = new User();int sum = 10000000;apacheBeanUtilsCopyTest(user,target,sum);commonsPropertyCopyTest(user,target,sum);cglibBeanCopyTest(user,target,sum);springBeanCopyTest(user,target,sum);}private static void apacheBeanUtilsCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {apacheBeanUtilsCopy(source,target);}stopWatch.stop();System.out.println("使用org.apache.commons.beanutils.BeanUtils方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.apache.commons.beanutils.BeanUtils方式*/private static void apacheBeanUtilsCopy(User source, User target) {try {BeanUtils.copyProperties(source, target);} catch (Exception e) {}}private static void commonsPropertyCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {commonsPropertyCopy(source,target);}stopWatch.stop();System.out.println("使用org.apache.commons.beanutils.PropertyUtils方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.apache.commons.beanutils.PropertyUtils方式*/private static void commonsPropertyCopy(User source, User target) {try {PropertyUtils.copyProperties(target, source);} catch (Exception e) {}}private static void cglibBeanCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {cglibBeanCopy(source,target);}stopWatch.stop();System.out.println("使用org.springframework.cglib.beans.BeanCopier方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.springframework.cglib.beans.BeanCopier方式*/static BeanCopier copier = BeanCopier.create(User.class, User.class, false);private static void cglibBeanCopy(User source, User target) {copier.copy(source, target, null);}private static void springBeanCopyTest(User source, User target, int sum) {StopWatch stopWatch = new StopWatch();stopWatch.start();for (int i = 0; i < sum; i++) {springBeanCopy(source,target);}stopWatch.stop();System.out.println("使用org.springframework.beans.BeanUtils.copyProperties方式赋值"+sum+"个user对象,耗时:"+stopWatch.getLastTaskTimeMillis()+"毫秒");}/*** org.springframework.beans.BeanUtils.copyProperties方式*/private static void springBeanCopy(User source, User target) {org.springframework.beans.BeanUtils.copyProperties(source, target);}
}

“四大金刚” 性能统计
在这里插入图片描述

不测不知道,一测吓一跳,差的还真的多。

spring cglib BeanCopier性能最好,apache BeanUtils性能最差。

性能走势 --> spring cglib BeanCopier优于 spring copyProperties优于 apache PropertyUtils优于 apache BeanUtils

避免用Apache Beanutils进行属性的copy的问题 上面分析完了,下面再看看其它的方法做了哪些优化。

Apache PropertyUtils 源码分析
从源码可以清晰的看到,类型检查变成了非空校验,去掉了每一次copy的日志记录,性能肯定更好了。

类型检查变成了非空校验
去掉了每一次copy的日志记录
实际赋值的地方由copyProperty变成了DanyBean + setSimpleProperty;
DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能。

public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {// 判断数据源和目标对象不是nullif (dest == null) {throw new IllegalArgumentException("No destination bean specified");} else if (orig == null) {throw new IllegalArgumentException("No origin bean specified");} else {// 删除了org.apache.commons.beanutils.BeanUtils.copyProperties中最为耗时的log日志记录int var5;int var6;String name;Object value;// 类型检查if (orig instanceof DynaBean) {// 获取源对象所有属性DynaProperty[] origDescriptors = ((DynaBean)orig).getDynaClass().getDynaProperties();DynaProperty[] var4 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {DynaProperty origDescriptor = var4[var6];// 获取源对象属性名name = origDescriptor.getName();// 判断源对象是否可读、判断目标对象是否可写if (this.isReadable(orig, name) && this.isWriteable(dest, name)) {try {// 获取对应的值value = ((DynaBean)orig).get(name);// 相对于org.apache.commons.beanutils.BeanUtils.copyProperties此处有优化// DanyBean 提供了可以动态修改实现他的类的属性名称、属性值、属性类型的功能if (dest instanceof DynaBean) {((DynaBean)dest).set(name, value);} else {// 每个属性都调用一次copyPropertythis.setSimpleProperty(dest, name, value);}} catch (NoSuchMethodException var12) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var12);}}}}} else if (orig instanceof Map) {Iterator entries = ((Map)orig).entrySet().iterator();while(true) {Map.Entry entry;String name;do {if (!entries.hasNext()) {return;}entry = (Map.Entry)entries.next();name = (String)entry.getKey();} while(!this.isWriteable(dest, name));try {if (dest instanceof DynaBean) {((DynaBean)dest).set(name, entry.getValue());} else {this.setSimpleProperty(dest, name, entry.getValue());}} catch (NoSuchMethodException var11) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var11);}}}} else {PropertyDescriptor[] origDescriptors = this.getPropertyDescriptors(orig);PropertyDescriptor[] var16 = origDescriptors;var5 = origDescriptors.length;for(var6 = 0; var6 < var5; ++var6) {PropertyDescriptor origDescriptor = var16[var6];name = origDescriptor.getName();if (this.isReadable(orig, name) && this.isWriteable(dest, name)) {try {value = this.getSimpleProperty(orig, name);if (dest instanceof DynaBean) {((DynaBean)dest).set(name, value);} else {this.setSimpleProperty(dest, name, value);}} catch (NoSuchMethodException var10) {if (this.log.isDebugEnabled()) {this.log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", var10);}}}}}}
}

通过 jvisualvm.exe 检测代码性能
再通过jvisualvm.exe检测一下运行情况,果然,logging.log4j没有了,其他的基本不变。
在这里插入图片描述
Spring copyProperties 源码分析
判断数据源和目标对象的非空判断改为了断言;
每次copy没有日志记录;
没有if (orig instanceof DynaBean) {这个类型检查;
增加了放开权限的步骤;

private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,@Nullable String... ignoreProperties) throws BeansException {// 判断数据源和目标对象不是nullAssert.notNull(source, "Source must not be null");Assert.notNull(target, "Target must not be null");/*** 若target设置了泛型,则默认使用泛型* 若是 editable 是 null,则此处忽略* 一般情况下editable都默认为null*/Class<?> actualEditable = target.getClass();if (editable != null) {if (!editable.isInstance(target)) {throw new IllegalArgumentException("Target class [" + target.getClass().getName() +"] not assignable to Editable class [" + editable.getName() + "]");}actualEditable = editable;}// 获取target中全部的属性描述PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);// 需要忽略的属性List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);for (PropertyDescriptor targetPd : targetPds) {Method writeMethod = targetPd.getWriteMethod();// 目标对象存在写入方法、属性不被忽略if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());if (sourcePd != null) {Method readMethod = sourcePd.getReadMethod();/*** 源对象存在读取方法、数据是可复制的* writeMethod.getParameterTypes()[0]:获取 writeMethod 的第一个入参类型* readMethod.getReturnType():获取 readMethod 的返回值类型* 判断返回值类型和入参类型是否存在继承关系,只有是继承关系或相等的情况下,才会进行注入*/if (readMethod != null &&ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {try {// 放开读取方法的权限if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {readMethod.setAccessible(true);}// 通过反射获取值Object value = readMethod.invoke(source);// 放开写入方法的权限if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {writeMethod.setAccessible(true);}// 通过反射写入值writeMethod.invoke(target, value);}catch (Throwable ex) {throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", ex);}}}}}
}
总结
阿里的友情提示,避免用Apache Beanutils进行对象的copy,还是很有道理的。Apache Beanutils的性能问题出现在类型校验和每一次copy的日志记录;Apache PropertyUtils 进行了如下优化:
类型检查变成了非空校验
去掉了每一次copy的日志记录
实际赋值的地方由copyProperty变成了DanyBean + setSimpleProperty;
Spring copyProperties 进行了如下优化:
判断数据源和目标对象的非空判断改为了断言;
每次copy没有日志记录;
没有if (orig instanceof DynaBean) {这个类型检查;
增加了放开权限的步骤;

相关文章:

Apache Beanutils为什么被禁止使用?

收录于热门专栏Java基础教程系列&#xff08;进阶篇&#xff09; 在实际的项目开发中&#xff0c;对象间赋值普遍存在&#xff0c;随着双十一、秒杀等电商过程愈加复杂&#xff0c;数据量也在不断攀升&#xff0c;效率问题&#xff0c;浮出水面。 问&#xff1a;如果是你来写…...

sql server执行md5加密的时候,字符串前带N和不带N的结果是不一样的

最近因为项目的需要&#xff0c;报表中需要对数据进行MD5加密&#xff0c;结果报表系统得出来的sql语句&#xff0c;字符串前都自动带了N&#xff0c;执行时&#xff0c;发现得到的结果跟在数据库中执行的sql&#xff08;字符串不带N&#xff09;得的值不一样&#xff0c;最后自…...

01Python编译器和编辑器下载

Python下载 通过python官网下载:https://www.python.org/因为python官网的服务器在国外,我们可以通过腾讯软件中心下载https://pc.qq.com/search.html#!keyword=python 腾讯软件中心下载请使用普通下载,其他什么下载会自动帮你下个电脑管家(没必要) python简单描述 python…...

CHAPTER 5 自动发现、自动注册、分布式监控、SNMP监控

自动发现与自动注册5.1 自动发现与自动注册5.1.1 简介5.1.2 两种模式5.2 自动发现--被动模式5.3 自动注册--主动模式5.4 分布式监控5.4.1 介绍5.4.2 配置zabbix proxy5.5 SNMP监控5.5.1 使用范围5.5.2 安装snmp程序5.5.3 配置snmp程序5.5.4 测试snmp5.5.5 在web界面进行配置5.1…...

P5311 [Ynoi2011] 成都七中

题目描述 给你一棵 nnn 个节点的树&#xff0c;每个节点有一种颜色&#xff0c;有 mmm 次查询操作。 查询操作给定参数 lrxl\ r\ xl r x&#xff0c;需输出&#xff1a; 将树中编号在 [l,r][l,r][l,r] 内的所有节点保留&#xff0c;xxx 所在连通块中颜色种类数。 每次查询操…...

Python 日期和时间格式

Python 程序能用很多方式处理日期和时间&#xff0c;转换日期格式是一个常见的功能。Python 提供了一个 time 和 calendar 模块可以用于格式化日期和时间。时间间隔是以秒为单位的浮点小数。每个时间戳都以自从1970年1月1日午夜&#xff08;历元&#xff09;经过了多长时间来表…...

电脑和手机的软件推荐

安卓软件 jota text 记事本 x浏览器 &#xff08;支持禁js&#xff0c;支持嗅探 视频 音频&#xff09; __ 空缺 暂未能发现好用的office软件 snapseed图片调整 可谓手机界的photoshop vidtrim视频剪辑 librera reader &#xff08;无广告 电子书软件 但是发音很差 lithum或者…...

酸回收树脂的应用

酸洗废水 在轧钢、金属表面处理、电子元件制造等过程中需要清除钢材表面氧化铁皮而使用酸进行酸洗&#xff0c;酸洗过程中会产生废酸液和酸洗废水。 这些废酸产量大、酸度高&#xff0c;而且由于酸洗废水来自钢铁和金属表面处理的清洗水&#xff0c;水中含有多种重金属离子&am…...

windows上配置IIS全过程

文章目录1️⃣ 配置IIS1.1 从开始打开服务器管理1.2 添加角色和功能1.3 添加角色和功能向导1.4 按照如下步骤选择2️⃣ 问题&#xff1a;缺少源文件解决方案优质资源分享作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/1…...

软考高级信息系统项目管理师系列之十三:项目成本管理

软考高级信息系统项目管理师系列之十三:项目成本管理 一、成本管理领域输入、输出、工具和技术表二、成本管理基础知识点1.成本类型2.应急储备和管理储备3.成本基准三、项目成本管理过程1.项目成本管理的过程2.成本管理计划3.项目成本估算的主要步骤4.活动成本估算5.项目预算6…...

HIVE 基础(一)

目录 启动hive 方式一 方式二 修改hdfs上给定文件执行的读写权限 创建数据库 查看数据库 查看数据库详细信息 查看当前数据库 创建表 查看建表语句 查看表信息 删除表 添加数据 查看表数据 删除数据库 强制删除数据库 启动hive 方式一 [roothadoop1 ~]# hive 方…...

《狂飙》壁纸太帅,Python自动切换太酷(8)

小朋友们好&#xff0c;大朋友们好&#xff01;我是猫妹&#xff01;要说最近什么电视剧最火&#xff1f;非《狂飙》莫属。《狂飙》剧名来自毛主席诗词“国际悲歌歌一曲&#xff0c;狂飙为我从天落”。导演借用“狂飙”二字来比喻剧中的扫黑除恶大风暴。据了解&#xff0c;《狂…...

博客排名的影响是什么? 说明优点、注册方法和推荐网站

如果您经营博客&#xff0c;您是否在博客排名网站上注册&#xff1f;博客排名网站是以排名格式介绍各种注册博客的网站。如果您注册博客&#xff0c;您将有更多机会被人们看到&#xff0c;并且可以期望增加访问权限。对于那些刚刚打开博客并担心访问量不会轻易增加的人来说&…...

全流程GMS地下水数值模拟技能培养及溶质运移反应问题深度解析实践技术

本次综合前期多次学习的效果及重点关注环节&#xff0c;系统性呈现地下水数值模拟软件GMS建模方法同时&#xff0c;建立与实践项目过程中的重点问题相融合&#xff0c;在教学中不仅强调学习三维地质结构建模、水文地质模型概化、边界条件设定、参数反演和模型校核等关键环节&am…...

【软件架构设计】SOA/软件架构设计---面向服务的架构(SOA详细解释)

文章目录面向服务的架构SOA 概述1. 服务的基本结构2.SOA 设计原则3. 服务构件与传统构件SOA 的关键技术1. UDDI2.WSDL3.SOAP4.RESTSOA 的实现方法1.Web Service2. 服务注册表3. 企业服务总线微服务1.微服务的优势2. 微服务面临的挑战3.微服务与 SOA面向服务的架构 迄今为止&am…...

erupt框架Ueditor富文本编辑器图片上传出现405异常

最近在研究erupt框架(v1.11.2),当字段使用Ueditor富文本编辑器,在图片上传的时候出现405异常,接口不支持POST请求方式: 根据错误提示找到对应的源码,发现Handler方法只支持GET请求,而图片上传的时候是以POST方式发起请求的; 此时需要修改源码,用自定义的类覆盖jar包中同名的…...

FILE文件操作

文件指针 每个被使用的文件都在内存中开辟了一个相应的文件信息区&#xff0c;用来存放文件的相关信息&#xff08;如文件的名 字&#xff0c;文件状态及文件当前的位置等&#xff09;。这些信息是保存在一个结构体变量中的。该结构体类型是有系统 声明的&#xff0c;取名FILE…...

SAP PP工单确认完成(CNF)状态取消方法

这SAP PP工单确认完成&#xff08;CNF&#xff09;状态取消方法SAP PP工单确认完成&#xff08;CNF&#xff09;状态取消方法SAP PP工单确认完成&#xff08;CNF&#xff09;状态取消方法 工单完工后取消了其中的一个报工&#xff0c;然后无法再报工 此时再报工&#xff0c;系…...

Python 采集 筷 实现视频批量保存

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 刷到的视频怕它下架&#xff1f;我们来采集保存一下它 知识点: 动态数据抓包 requests发送请求 json数据解析 开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 requests pip install requests 代码展示 需…...

关于linux下环境配置遇到的坑

1、输入终端命令和vi时&#xff0c;一定要确认是英文输入法&#xff01; 比如中英文输入下的短杠号“-”是不同的&#xff0c;虽然看起来一样。如果是中文输入法下输入含有短杠号的命令&#xff0c;会导致很多意料之外的错误。比如在用sudo ln -s 创建软连接时&#xff0c;会提…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...