在使用Fileupload组件处理文件上传时,我们可以定义maxInMemorySize,当上传文件大小超过此值,则把文件写入临时文件,防止内存占用过多或溢出。如下配置代码。
@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(1024 * 1024 * maxUploadSize);
multipartResolver.setDefaultEncoding("utf-8");
multipartResolver.setUploadTempDir(new FileSystemResource(uploadTempDir));
multipartResolver.setMaxInMemorySize(maxInMemorySize);
return multipartResolver;
}
那么当临时文件被服务器端写入到硬盘后是合适删除的呢,下面是FileCleaningTracker的源码,分析了fileupload是如何自动删除文件的。
package org.apache.commons.io;
import java.io.File;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
public class FileCleaningTracker {
//引用队列,当Reference内关联的对象被GC时会把当前Reference加入到此队列。
ReferenceQueue<Object> q = new ReferenceQueue<>();
//Tracker继承了PhantomReference(虚引用),内部封装了文件路径。
//此类负责强引用Tracker,因为Tracker类不能被GC,所以要用引用保存它。
final Collection<Tracker> trackers = Collections.synchronizedSet(new HashSet<Tracker>()); // synchronized
//删除失败的文件路径集合
final List<String> deleteFailures = Collections.synchronizedList(new ArrayList<String>());
//指示此类是否完成任务
volatile boolean exitWhenFinished = false;
//工作线程
Thread reaper;
//加入任务,同步方法线程安全
private synchronized void addTracker(final String path, final Object marker, final FileDeleteStrategy
deleteStrategy) {
// synchronized block protects reaper
if (exitWhenFinished) {
throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
}
//工作线程第一次需要初始化,后面看Reaper的解释
if (reaper == null) {
reaper = new Reaper();
reaper.start();
}
//在trackers集合中加入Tracker对象,Tracker对象包含了path[文件路径],deleteStrategy[删除策略], marker[监控的对象], q[引用队列]
trackers.add(new Tracker(path, deleteStrategy, marker, q));
}
public synchronized void exitWhenFinished() {
// synchronized block protects reaper
exitWhenFinished = true;
if (reaper != null) {
synchronized (reaper) {
reaper.interrupt();
}
}
}
//工作线程
private final class Reaper extends Thread {
/** Construct a new Reaper */
Reaper() {
super("File Reaper");
setPriority(Thread.MAX_PRIORITY);
setDaemon(true);
}
@Override
public void run() {
// thread exits when exitWhenFinished is true and there are no more tracked objects
while (exitWhenFinished == false || trackers.size() > 0) {
try {
//q.remove()阻塞方法,有对象GC时Tracker会加入到q中,这里可以remove出来。
final Tracker tracker = (Tracker) q.remove();
//从set中移除强引用
trackers.remove(tracker);
//删除临时文件
if (!tracker.delete()) {
//删除失败加入记录
deleteFailures.add(tracker.getPath());
}
//清楚对象引用
tracker.clear();
} catch (final InterruptedException e) {
continue;
}
}
}
}
//继承PhantomReference
private static final class Tracker extends PhantomReference<Object> {
//文件路径
private final String path;
//删除策略
private final FileDeleteStrategy deleteStrategy;
Tracker(final String path, final FileDeleteStrategy deleteStrategy, final Object marker,
final ReferenceQueue<? super Object> queue) {
super(marker, queue);
this.path = path;
this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy;
}
public String getPath() {
return path;
}
//删除临时文件
public boolean delete() {
return deleteStrategy.deleteQuietly(new File(path));
}
}
}