我们有一个传统系统,其中有一个管理模块,允许用户上传jar文件。上传后,会对jar文件进行验证,如果不符合内部规则,则会被删除。
问题在于,Windows会抛出一个异常,告诉我该文件“已经被其他进程使用”。(当我调用
首先,我们使用primefaces(4.0)上传文件。Primefaces依赖于commons-fileupload(1.3.1)。它调用以下方法:
在使用NIO Files.write之前,我一直在使用“标准”的Java IO类。问题与上面的代码无关,因为如果我注释掉对validateJar的调用,Files.delete(tmpJar)将被成功执行并删除文件。所以,问题与下面的代码有关,但我找不到具体位置... Job是一个内部类,基本上是一个简单的POJO。 "jobAnnotation"是一个自定义注解,用于识别作业。我已经缩短了代码,但保留了基本部分。
问题在于,Windows会抛出一个异常,告诉我该文件“已经被其他进程使用”。(当我调用
Files.delete(tmpJar)
时)。我无法确定为什么该文件被打开了。对我来说,似乎我已经关闭了所有东西。首先,我们使用primefaces(4.0)上传文件。Primefaces依赖于commons-fileupload(1.3.1)。它调用以下方法:
public void handleFileUpload(FileUploadEvent event) {
Path tmpJar = null;
try {
tmpJar = Files.createFile(Paths.get(event.getFile().getFileName()));
Files.write(tmpJar, event.getFile().getContents());
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
if (tmpJar != null) {
try {
this.validateJar(tmpJar.toString());
Files.delete(tmpJar);
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}
在使用NIO Files.write之前,我一直在使用“标准”的Java IO类。问题与上面的代码无关,因为如果我注释掉对validateJar的调用,Files.delete(tmpJar)将被成功执行并删除文件。所以,问题与下面的代码有关,但我找不到具体位置... Job是一个内部类,基本上是一个简单的POJO。 "jobAnnotation"是一个自定义注解,用于识别作业。我已经缩短了代码,但保留了基本部分。
private List<Job> validateJar(final String jarPath) throws IOException {
List<Job> jobs = new ArrayList<Job>();
try (JarFile jarFile = new JarFile(jarPath)) {
URL[] jars = { new URL("file:" + jarPath) };
ClassLoader jobClassLoader = URLClassLoader.newInstance(jars, this.getClass().getClassLoader());
Enumeration<JarEntry> jarEntries = jarFile.entries();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
String className = jarEntry.getName();
Class<?> classToLoad;
try {
classToLoad = Class.forName(className, true, jobClassLoader);
} catch (Exception e1) {
LOGGER.error(e1.getMessage(), e1);
continue;
}
if (classToLoad.isAnnotationPresent(jobAnnotation)) {
String vlr = null;
try {
Class<?> jobClass = (Class<?>) Class.forName(classToLoad.getCanonicalName(), true, jobClassLoader);
Annotation annotation = jobClass.getAnnotation(jobAnnotation);
Method method = annotation.getClass().getMethod("getValue");
vlr = ((String) method.invoke(annotation, new Object[0]));
} catch (Exception e1) {
LOGGER.error(e1.getMessage(), e1);
}
Job job = new Job();
job.setEnabled(true);
job.setJarfile(jarPath);
job.setClassName(classToLoad.getName());
Parameter parameter = new Parameter();
parameter.setRequired(true);
parameter.setName("name");
parameter.setValue(vlr);
job.addParameter(parameter);
jobs.add(job);
}
}
} catch (IOException e) {
throw e;
}
return jobs;
}
在使用try-with-resources之前,我使用普通的try-catch-finally来关闭JarFile,因为这是唯一有显式close方法的东西。可能是类加载正在保持文件打开,但我不知道如何关闭它。
我进行了一些搜索,发现无法卸载类(在Java中卸载类?)。
所以,问题是如何释放它?或者如何删除文件?
顺便说一下,我正在使用Java 1.7.0_71、JBoss 7.1.1和Windows 7(64位)。