2

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

加载器遍历一个文件夹并对任何扩展名为 .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 ,所有依赖关系都会得到解决吗?

4

2 回答 2

1

从 URLCLassLoader 的文档中:

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

因此,您必须对目录或 .jar 使用 URL

两种解决方案:

  1. 强制您的用户向您提供 .jar 文件,包括某种清单,其中包含他们希望加载的类名。Bukkit开发人员使用这种方法。过去使用过这种方法,依赖项应该都打包在 .jar 文件中,因此在 URLClassLoader 的搜索路径中并能够加载。
  2. 使用文件目录的 URL,并在该目录中搜索 .class 文件。我不确定是否会使用此方法加载依赖项。
于 2012-06-01T21:54:24.683 回答
1

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

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

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

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

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

于 2012-06-01T22:16:02.030 回答