资源未发布

时间:2014-12-30 15:57:17

标签: java classloader

我们有一个遗留系统,它有一个admim模块,允许用户上传jar文件。上传后,jar文件将被验证,如果不符合内部规则,则会被删除。

问题是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方法的东西。可能是打开文件的类加载,但我不知道如何关闭它。

我做了一些搜索,发现我无法卸载课程(Unloading classes in java?)。

所以,问题是,我该如何发布它?或者我该如何删除文件?

BTW,我使用java 1.7.0_71,jboss 7.1.1,windows 7(64)。

3 个答案:

答案 0 :(得分:1)

URLClassLoader类已经有一个close()方法。 close()方法将关闭使用URLClassLoader打开的任何Jar文件。这应该可以防止“文件已经在使用”异常。

答案 1 :(得分:0)

File is already being used by another process.说这可能不是你的错,也许只是另一个应用程序使用该文件。您可以查看this question以查找用于您文件的流程。

答案 2 :(得分:0)

某些病毒扫描程序软件在检查JAR时需要很长时间。尝试禁用Virusscanner。其他候选者可以是Windows索引器进程,也可以是explorer.exe本身。如果您没有找到文件锁定的任何原因,请尝试在验证和删除之间延迟。也许你需要一个多次尝试的循环。