在上一篇文章中我们主要介绍了 tomcat nio 中的长连接,包括长连接开启和关闭的条件,每个长连接可以复用的请求数目等等,在这里我们介绍 tomcat 对文件上传的支持。
文件上传的 trigger 文件上传的本质
文件上传的trigger
文件上传的本质
// parseParts() method in org.apache.catalina.connector.RequestString locationStr = mce.getLocation();if (locationStr == null || locationStr.length() == 0) {location = ((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR));} else {location = new File(locationStr);if (!location.isAbsolute()) {location = new File((File) context.getServletContext().getAttribute(ServletContext.TEMPDIR), locationStr).getAbsoluteFile();}}
文件位置由配置 muti-part location 决定,如果没有该配置, 那么该位置将会由上下文属性ServletContext.TEMPDIR(javax.servlet.context.tempdir) 决定,一般值为 tomcat 工作目录中的 Tomcat/${FQDN}/${Context} 。 以下例子我们在 basic-service 上下文的项目里上传两张图片,由上传结果可以看到文件在工作目录下的 Tomcat/localhost/basic-service 中,并且物理文件名字已经改变(但是通过getPart()依然可以得到原始文件名字,大小等信息)


调用消费 servlet 输入流相关的 API 会完成对上传文件的支持,如 getParameter() 和 getPart() 等相关 API。
文件上传的本质是把文件写到 tomcat 工作目录的磁盘中,由 getPart() 相关 API 得到磁盘中文件的大小,文件名,输入流等信息,然后根据业务逻辑进行操作。
这样的上传方式需要考虑空间大小,因为文件保存在磁盘上,长时间不清理会占用大量空间。当然一些框架(如springmvc)对于 muti-part 请求的处理已经帮我们自动清理了上传的文件,但是如果在并发上传文件比较多的时候,依然会占用大量的磁盘空间。
这样的上传方式需要考虑 os 权限问题,因为是保存在磁盘上,所以我们的 java 进程必须要对这个目录有读写权限。当然如果是默认配置,路径在 tomcat 工作目录下,是不需要过多担心权限问题的。但是如果配置了其他路径,就需要考虑权限问题。
这样的上传方式有效率问题,从应用程序角度看,读取文件流有一系列步骤,即文件从网络设备写入磁盘文件,文件再从磁盘读入应用程序。


上面涉及了网络设备,操作系统内核空间,磁盘设备,tomcat 自身应用空间,开发者应用空间的几次切换,当文件比较大的时候会费时间,从优化角度来说我们一般采用流式上传来避免多次切换。





