深度分析Fileupload是如何删除临时文件的

 

在使用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));
        }
    }

}

 

上一篇:javaE中获取项目properties文件中的常量数据


下一篇:FileUpload无法赋值解决方案