java - 资源未释放

标签 java classloader

我们有一个遗留系统,它有一个允许用户上传 jar 文件的 admim 模块。上传后,对 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,这是唯一具有显式关闭方法的东西。可能是类加载使文件保持打开状态,但我不知道如何关闭它。

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

那么,问题来了,我该如何发布呢?或者如何删除文件?

顺便说一句,我使用的是 java 1.7.0_71、jboss 7.1.1、windows 7 (64)。

最佳答案

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

关于java - 资源未释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27708526/

相关文章:

java - 如何将我的数据从 csv 文件获取到 DataProvider

Java 类加载器 - 在私有(private)类中调用静态方法

java - Java Attach API 的限制和范围

java - 运行我的应用程序的 EntityManager 没有持久性提供程序

java - Play中的Hot redeploy和Spring Boot中的自动重启的区别

java - 当我使用自定义类加载器时出现 ClassCastException

java - 来自 JUnit 的 getResourceAsStream

java - 设置合成的背景图像,使内部合成不显示背景

java - Base64 解码并解压缩字符串

java - 如果复选框已被选中,如何存储?