Java 未释放的资源

Java 未释放的资源,java,classloader,Java,Classloader,我们有一个遗留系统,它有一个允许用户上传jar文件的admim模块。上传后,将验证jar文件,如果不符合内部规则,则将其删除 问题是windows正在抛出一个异常,告知文件“已被另一个进程使用。”(当我调用Files.delete(tmpJar);)。我无法确定文件打开的原因。在我看来,我已经关闭了一切 首先,我们使用primefaces(4.0)上传文件。Primefaces依赖于commons文件上传(1.3.1)。它调用以下方法: public void handleFileUpload(

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

问题是windows正在抛出一个异常,告知文件“已被另一个进程使用。”(当我调用
Files.delete(tmpJar);
)。我无法确定文件打开的原因。在我看来,我已经关闭了一切

首先,我们使用primefaces(4.0)上传文件。Primefaces依赖于commons文件上传(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;
}
private List validateJar(最终字符串jarPath)引发IOException{
列表作业=新建ArrayList();
try(JarFile JarFile=newjarfile(jarPath)){
URL[]jars={newurl(“文件:+jarPath)};
ClassLoader jobClassLoader=URLClassLoader.newInstance(jars,this.getClass().getClassLoader());
枚举jarEntries=jarFile.entries();
while(jarEntries.hasMoreElements()){
JarEntry JarEntry=jarEntries.nextElement();
字符串className=jarEntry.getName();
类装载;
试一试{
classToLoad=Class.forName(className,true,jobClassLoader);
}捕获(异常e1){
LOGGER.error(e1.getMessage(),e1);
继续;
}
if(classToLoad.isAnnotationPresent(jobAnnotation)){
字符串vlr=null;
试一试{
类jobClass=(类)Class.forName(classToLoad.getCanonicalName(),true,jobClassLoader);
Annotation=jobClass.getAnnotation(jobAnnotation);
Method=annotation.getClass().getMethod(“getValue”);
vlr=((String)method.invoke(注释,新对象[0]);
}捕获(异常e1){
LOGGER.error(e1.getMessage(),e1);
}
作业=新作业();
job.setEnabled(true);
setJarfile(jarPath);
job.setClassName(classToLoad.getName());
参数=新参数();
参数.setRequired(true);
参数.setName(“名称”);
参数设置值(vlr);
job.addParameter(参数);
jobs.add(job);
}
}
}捕获(IOE异常){
投掷e;
}
返回工作岗位;
}
在使用try with resources之前,我使用了常规的try-catch-finally来关闭JarFile,这是唯一有显式close方法的东西。可能是类加载使文件保持打开状态,但我不知道如何关闭它

我做了一些搜索,发现无法卸载类()

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


顺便说一下,我正在使用Java1.7.0_71,JBoss7.1.1,windows 7(64)。

文件已经被另一个进程使用。
说这可能不是您的错,可能只是使用了另一个应用程序。您可以通过检查查找文件中使用的进程。

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

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

URLClassLoader类有一个close()方法,您可以尝试使用它吗?close()方法将关闭使用URLClassLoader打开的任何Jar文件。如果关闭ClassLoader不起作用,您可以尝试使用字节码解释器,这样您就可以像打开普通文件一样打开.class文件,并完全控制关闭文件的时间@codelion将您的评论作为答案,这样我就可以结束我的问题,接受您的答案。成功了。我的错误是我使用接口创建类加载器--classloader jobClassLoader=URLClassLoader.newInstance(jars,this.getClass().getClassLoader());--而且它没有close()方法。所以我改为--URLClassLoader jobClassLoader=URLClassLoader.newInstance(jars,this.getClass().getClassLoader());--然后我打电话给close,结果它成功了…@BobRivers啊,很高兴知道它成功了!如果您看到他的代码,那么他正在打开jar文件并使用URLClassLoader加载,因此不是另一个应用程序在使用该文件。