Java 类装入器无法装入模块



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

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

这是排除的 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没有被破解,所有的依赖关系都会被解决吗?

来自 URLCLassLoader 的文档:

此类装入器用于从引用 JAR 文件和目录。任何以"/"结尾的 URL 都假定引用目录。 否则,假定 URL 引用将根据需要打开的 JAR 文件。

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

两种解决方案:

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

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

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

但是,通常类加载器不会"包含"所有这些类,例如,您的类最终将从java.lang.Object继承,而URLClassLoader将不包含Object.class文件。因此,类装入器委派给其父类装入器。

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

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

最新更新