commons-fileupload框架源码解析(七)--FileCleaningTracker

  1. commons-fileupload框架源码解析(一)--实例
  2. commons-fileupload框架源码解析(二)--HTTP
  3. commons-fileupload框架源码解析(三)--ParseRequest
  4. commons-fileupload框架源码解析(四)--FileItemIterator
  5. commons-fileupload框架源码解析(五)--MultipartStream
  6. commons-fileupload框架源码解析(六)--ParameterParser
  7. commons-fileupload框架源码解析(七)--FileCleaningTracker
  8. commons-fileupload框架源码解析(八)--DeferredFileOutputStream

FileCleaningTracker

简介

FileCleaningTracker是一个文件清理的跟踪器。而他不是简单的通过定时器来定时清理文件,而是使用跟踪GC来清理文件,我觉得这个方法很优秀,因为通过GC跟踪比起定时器,更加少占用cpu的资源时间,也是能保证FileCleaningTracker能够像GC一样,根据服务器的情况做出相关处理,而不是。

成员变量

/**
     * Queue of Tracker instances being watched.
     * 跟踪GC回收情况的引用队列,Tracker的marker对象时,会先将Tracker放在这个队列中,在下次GC时,如果q中出栈了对应的Tracker后,就会清掉这个Tracker
     */
    ReferenceQueue q = new ReferenceQueue<>();
    /**
     * Collection of Tracker instances in existence.
     * Trackers集合
     */
    final Collection trackers = Collections.synchronizedSet(new HashSet()); // synchronized
    /**
     * Collection of File paths that failed to delete.
     * 删除失败集合,里面包含所有删除失败的临时文件路径
     */
    final List deleteFailures = Collections.synchronizedList(new ArrayList());
    /**
     * Whether to terminate the thread when the tracking is complete.
     * 终止标记
     */
    volatile boolean exitWhenFinished = false;
    /**
     * The thread that will clean up registered files.
     * 个守护线程,用于根据GC的回收情况去删除临时文件
     */
    Thread reaper;
 
 

track(File,Object,FileDeleteStrategy)

  public void track(final String path, final Object marker, final FileDeleteStrategy deleteStrategy) {
        if (path == null) {
            throw new NullPointerException("The path must not be null");
        }
        addTracker(path, marker, deleteStrategy);
    }

具体业务要看addTracker

addTracker(String,marker,FileDeleteStrategy)

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");
        }
        if (reaper == null) {
            reaper = new Reaper();
            reaper.start();
        }
        trackers.add(new Tracker(path, deleteStrategy, marker, q));
    }

只是根据参数,封装到Tracker中,并将Trecker添加到Trackers中。Reaper是个线程,懒汉式去初始化了Reaper

Reaper

    private final class Reaper extends Thread {
        /** Construct a new Reaper */
        Reaper() {
            super("File Reaper");
            setPriority(Thread.MAX_PRIORITY);//线程优先级,值越大,优先级越低,这里设置了线程最低的优先级
            ////设置成守护线程,守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
            // 也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。
            // 那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出。
            setDaemon(true);
        }

        /**
         * Run the reaper thread that will delete files as their associated
         * marker objects are reclaimed by the garbage collector.
         */
        @Override
        public void run() {
            // thread exits when exitWhenFinished is true and there are no more tracked objects
            while (exitWhenFinished == false || trackers.size() > 0) {
                try {
                    // Wait for a tracker to remove.
                    //当ReferenceQueue有对象时,remove就会激活,否则一直等待
                    final Tracker tracker = (Tracker) q.remove(); // cannot return null
                    trackers.remove(tracker);
                    //删除文件
                    if (!tracker.delete()) {
                        deleteFailures.add(tracker.getPath());
                    }
                    tracker.clear();//解除PhantomReference的referent引用
                } catch (final InterruptedException e) {
                    continue;
                }
            }
        }
    }

是个守护线程,用于根据GC的回收情况去删除临时文件,当删除文件不成功时,会将会将删除失败的临时文件路径添加到delteFailures中

Tracker

 private static final class Tracker extends PhantomReference {

        /**
         * The full path to the file being tracked.
         */
        private final String path;
        /**
         * The strategy for deleting files.
         */
        private final FileDeleteStrategy deleteStrategy;

        /**
         * Constructs an instance of this class from the supplied parameters.
         *
         * @param path  the full path to the file to be tracked, not null
         * @param deleteStrategy  the strategy to delete the file, null means normal
         * @param marker  the marker object used to track the file, not null
         * @param queue  the queue on to which the tracker will be pushed, not null
         */
        Tracker(final String path, final FileDeleteStrategy deleteStrategy, final Object marker,
                final ReferenceQueue queue) {
            super(marker, queue);
            this.path = path;
            this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy;
        }

        /**
         * Return the path.
         *
         * @return the path
         */
        public String getPath() {
            return path;
        }

        /**
         * Deletes the file associated with this tracker instance.
         *
         * @return {@code true} if the file was deleted successfully;
         *         {@code false} otherwise.
         */
        public boolean delete() {
            return deleteStrategy.deleteQuietly(new File(path));
        }
    }
 
 

逻辑代码很简单,不过是根据删除策略去删除文件而已。令人费解的地方是Tracker继承了PhantomReference,PhantomReference是java中的虚引用,主要用于跟踪GC的回收情况,需要跟ReferenceQueue连用,当GC回收对象PhantomReference的referent时,会先将对象放进ReferenceQueue队列中,我们可以同ReferenceQueue.remove()方法,使得referent出栈,然后GC会在下一次回收对象的时候,查看referent是否还有被引用,没有就直接清理掉

FileDeleteStrategy

FileDeleteStrategy是删除策略,框架提供了两种,一种是NORMAL,另一种是FORCE,框架默认是使用NORMAL

    /**
     * The singleton instance for normal file deletion, which does not permit
     * the deletion of directories that are not empty.
     */
    public static final FileDeleteStrategy NORMAL = new FileDeleteStrategy("Normal");
    /**
     * The singleton instance for forced file deletion, which always deletes,
     * even if the file represents a non-empty directory.
     */
    public static final FileDeleteStrategy FORCE = new ForceFileDeleteStrategy();

FileDeleteStrategy.NORMAL

 public boolean deleteQuietly(final File fileToDelete) {
        if (fileToDelete == null || fileToDelete.exists() == false) {
            return true;
        }
        try {
            return doDelete(fileToDelete);
        } catch (final IOException ex) {
            return false;
        }
    }

   public void delete(final File fileToDelete) throws IOException {
        if (fileToDelete.exists() && doDelete(fileToDelete) == false) {
            throw new IOException("Deletion failed: " + fileToDelete);
        }
    }

最后是调用了File.delete()方法,删除的File是文件夹必须是空的,不然会删除失败。

FileDeleteStrategy.FORCE

  @Override
        protected boolean doDelete(final File fileToDelete) throws IOException {
            FileUtils.forceDelete(fileToDelete);//
            return true;
        }

调用的是FileUtils.forceDelete(File),删除的文件夹可以是空(递归删除文件夹下的子文件,最后删除该文件夹)

你可能感兴趣的:(commons-fileupload框架源码解析(七)--FileCleaningTracker)