前言
呵呵 最近在整理文件上传部分的东西的时候, 发现了一个问题
文件上传部分 有一些基础的问题, 可以参见 29 SpringMVC 上传文件未生成临时文件, 我们这里上传的文件的大小是 大于 sizeThreshold 的
SpringMVC 上传文件的时候会生成一个临时文件, 我想直接使用这个临时文件来处理业务, 但是 当真正的业务代码使用的时候 缺爆出了一个 FileNotFoundException
堆栈信息如下
java.io.FileNotFoundException: /upload/upload_7b3caa68_3623_49a0_a348_d7c6e436de02_00000008.tmp (No such file or directory)at java.io.FileInputStream.open0(Native Method)at java.io.FileInputStream.open(FileInputStream.java:195)at java.io.FileInputStream.<init>(FileInputStream.java:138)at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:194)at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:251)
// 再下面为业务代码, 省略掉
呵呵 接下来我们来看看
问题的现象
在 Service 接收到 外部 Controller 传进来的参数这里, 是能够拿到 文件的数据的, 可以看这里的 file.getInputStream
查看一下磁盘上面, 也可以查看到这个临时文件, 当然我这里 因为不是同一次的截图, 所以文件名称对不上
但是在 Service 代码的更深层级的业务代码里面 来获取文件数据, 却获取不到了
查看一下磁盘上面, 这里再来查看这个临时文件, 呵呵 就没了
问题的排查
呵呵 问题的排查方法也很简单, 既然是 文件在另外一个代码里面 获取不到了, 那么是不是 代码哪里删掉了 临时文件
我们来到 DiskFileItem.delete 里面打上一个断点, 呵呵 看下 哪里会触发文件的删除
首先看到的是 SpringMVC 的 DispatcherServlet 是触发了 DiskFileItem 的删除的, 这里跟踪一下 具体的代码 应该是在 业务处理完成之后 删除的文件
那么这时候, 请在回到上面的 "问题的现象", 来看一下 上面图中 有一个 Thread.currentThread.getName(), 虽然是同在 一个 Service 里面
但是处理 代码的线程是不一样的, http 线程中能够拿到 file, 然后之后 异步将业务委托给了 executorService 的线程
在我们这里的情况 显然是 在 http 线程处理完成之后, 清理掉了临时文件, 然后之后 executorService 的业务线程拿到了文件的元数据信息, 然后去 获取文件数据, 发现文件不在了, 抛出了 FileNotFoundException
另外还有在 Tomcat 的资源回收清理的过程中也会尝试 清理掉本次请求关联的临时的 applicationPart 的信息
参考
29 SpringMVC 上传文件未生成临时文件