MultipartFile类型接收上传文件报出的UncheckedIOException以及删除tomcat临时文件失败源码探索

1、描述异常背景:

因为需要分析数据,待处理excel文件的数据行数太大,手动太累,花半小时写了一个定制的数据入库工具,改成了通用的,整个项目中的万级别数据都在工具上分析,写SQL进行分析,但是遇到很疑惑的问题,文件上传结束收流时,tomcat的DisFileItem类的delete方法会自动调用,但是如果当前系统用户的权限不足,或是文件流在删除该临时文件之前未关闭都会导致删除失败,虽然接收流的业务操作都结束了,但是很是会报出糟心的UncheckedIOException:Cannot delete tomcat默认的临时文件路径+_00000000.tmp异常(剧透一下:运行时未关闭输入流,JVM还在等待用户关闭,存在引用无法回收,所以手动跟着路径去删除你都删不掉,所以跟着源码找根源)。

2、查找异常原因(并不是所有的异常都是你显式的写出来的,特别是轮子使用不仔细的内部异常)

以上请及其注意异常出现的根源:StandardServletMultipartResolver.java:134;

我们进去查看其源码得到

也就是说我们的请求文件接收成功了吗,但是删除临时文件的操作出现问题了:

java 复制代码
if (request.getFile(part.getName()) != null) {
                        part.delete();
   }

进入删除的代码下来:

注意这一句源码注释:

删除部件的基础存储,包括删除任何关联的临时磁盘文件。尽管容器将自动删除此存储,但此方法可用于确保在较早的时间执行此操作,从而保留系统资源。

仅当对部件实例进行垃圾回收时,才需要容器删除关联的存储。Apache Tomcat 将在关联的请求完成处理后删除关联的存储。其他容器的行为可能不同。

抛出:

IOException -- 如果在尝试删除部件时发生 I/O

那么我们进入到它的默认实现类的最终源码:

到这里我们大致是知道问题出在这个临时文件的删除上了。

但是为什么删除失败呢?只有可能是这行代码的问题:

如果输出的文件就是有问题的null那一定是删除不掉的,让我们找找源码:

这里一定是没有问题的,继续往下走:

由此处的信息可以知道作为缓冲的临时文件区域的输出流未完成,还在保持开启状态,很大的可能是缓冲前的输入的流还没完全关闭(我们明确知道的是在代码里获取了输入的流但是没有对流进行关闭),亦或有可能原本文件上传就是null(当然不可能了兄弟)

3、结合2查找真正导致输出文件流在删除之前关闭的原因

我们注意到简单的接口代码是:

java 复制代码
    @PostMapping("/upTopGoods")
    @ResponseBody
    public void upTopGoods(@RequestParam("fileName") MultipartFile fileName){
        if (Objects.nonNull(fileName)){
            excelUtil.setTopGoods(fileName);
        }
    }

这个流会在操作完成或输入流的字节被处理完之后没能主动关闭的话,很有可能出自于接口MultipartFile的性质需要我们自己关闭(所以才会有一次OOM异常,但是请注意一定不仅仅是这个导致的,BUG选手程序员要保持疑问)。

所以我们查看MultipartFile的源码试图找出问题所在:

以上是MultipartFile的输入流方法注释。

以上处理完数据之后我们对输入的流进行了关闭,测试一下看看是否解决了问题:

通过结果来看是完全没有问题的了。

本次排查问题寻根原理过程结束,拜拜!

相关推荐
明月(Alioo)9 分钟前
给 AI Agent 装上“大脑“:Java语言中Code Interpreter 的设计与实现
java·ai·agent
QuZero11 分钟前
StampedLock Mechanism
java·算法
Javatutouhouduan13 分钟前
Java小白如何快速玩转Redis?
java·数据库·redis·分布式锁·java面试·后端开发·java程序员
xuhaoyu_cpp_java15 分钟前
Spring学习(一)
java·经验分享·笔记·学习·spring
kybs19911 小时前
springboot视频推荐系统--附源码72953
java·spring boot·python·eclipse·asp.net·php·idea
无限进步_1 小时前
C++ 多态机制完全解析:从虚函数重写到动态绑定原理
java·c语言·jvm·数据结构·c++·windows·后端
知识汲取者1 小时前
巨量引擎 Marketing API Java SDK 介绍
java·开发语言
182******20831 小时前
2026年40岁自学java还能找到工作吗
java·开发语言
yuzhiboyouye2 小时前
java线程池
java·开发语言·firefox
网络工程小王2 小时前
【LCEL 链式调用详解】调用篇-2
java·服务器·前端·数据库·人工智能