- commons-fileupload框架源码解析(一)--实例
- commons-fileupload框架源码解析(二)--HTTP
- commons-fileupload框架源码解析(三)--ParseRequest
- commons-fileupload框架源码解析(四)--FileItemIterator
- commons-fileupload框架源码解析(五)--MultipartStream
- commons-fileupload框架源码解析(六)--ParameterParser
- commons-fileupload框架源码解析(七)--FileCleaningTracker
- 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
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
逻辑代码很简单,不过是根据删除策略去删除文件而已。令人费解的地方是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),删除的文件夹可以是空(递归删除文件夹下的子文件,最后删除该文件夹)