Java Classloader无法加载模块?

时间:2012-06-01 21:41:57

标签: java classloader

我似乎遇到了在我正在开发的应用程序的模块加载器中加载类的问题。基本上,我将要加载的所有类都扩展了另一个类,它位于实际应用程序的包中。出于我们的目的,我们将其称为模块。模块位于实际应用程序之外的单独文件夹中。

加载器遍历一个文件夹并对任何扩展名为.class的文件执行 loadFile()方法。所有类都将包声明作为Module类,以及类头中的 extends Module 声明。

这是 loadFile()方法,不包括标题和例外条款:

String fileName = file.getName();
String className = fileName.replace(".class", ""); //Strips extension
Class<?> aClass = Class.forName(className, true, new URLClassLoader(new URL[] { file.toURI().toURL() }));
Class<? extends Module> modClass = aClass.asSubclass(Module.class);
return modClass.getConstructor().newInstance();

我在第三行继续得到 ClassNotFoundException 。过去,如果它没有被引发 ClassNotFoundException ,是否会解决所有依赖关系?

2 个答案:

答案 0 :(得分:1)

来自URLCLassLoader的文档:

  

此类加载器用于从引用的URL的搜索路径加载类和资源   JAR文件和目录。任何以“/”结尾的URL都被假定为引用目录。   否则,假定URL引用将根据需要打开的JAR文件。

因此,您必须使用目录或.jars

的URL

两种解决方案:

  1. 强制您的用户为您提供.jar文件,包括其中包含他们希望加载的类名的某种类型的清单。 Bukkit开发人员使用此方法。在过去使用过这个方法之后,依赖项应该全部打包在.jar文件中,从而打包在URLClassLoader的搜索路径中,并且能够加载。
  2. 使用文件目录的URL,并在该目录中搜索.class文件。我不确定是否会使用此方法加载依赖项。

答案 1 :(得分:1)

在URLClassLoader中,不要传递文件,而是传递父文件夹。但是,如果类都在“默认包”中,则此方法可以正常工作,因此要加载的.class文件不能在顶部包含包声明。

默认情况下,类加载器还会触发正确构建类所需的所有类的加载:它将尝试加载超类,超级超类等...所有接口和超级接口,所需的类对于静态字段和方法,方法签名所需的类(返回类型和参数)。它通常不会尝试加载方法内部使用的类,直到您执行这些方法。

但是,通常类加载器不会“包含”所有这些类,例如,您的类最终将继承自java.lang.Object,并且您的URLClassLoader将不包含Object.class文件。因此,类加载器委托给它们的父类加载器。

您当前正在创建URLClassLoader而没有指定父级,在Java 7中至少父级将默认为“系统类加载器”,只要您在普通的Java应用程序中,并且不执行代码就可以了。本身在类加载器的特定层次结构中。但是,如果您在Web应用程序或OSGI容器等中运行该代码,则应该为URLClassLoader提供一个适当的父代表,例如Thread.currentThread()。getContextClassLoader()或this.getClass() .getClassLoader()。

我想你需要所有这些,因为你需要在运行时动态加载这些类。