java - 链式类加载器难题

标签 java classloader

我在使用 Java 类加载器方面遇到了一些困难,也许有人可以解释一下这一点。我把问题的本质提炼如下:

共有三个类 - ClassLoaderTest , LoadedClassLoadedClassDep 。他们都走在不同的道路上。

ClassLoaderTest实例化一个新的 URLClassLoader -myClassLoader ,用剩余两个类的路径和它自己的类加载器(即应用程序类加载器)作为父类来启动它。然后它使用 Class.forName("com.example.LoadedClass", true, myClassLoader)加载LoadedClass通过反射(reflection)。 LoadedClass导入 LoadedClassDep 。如果我运行上面的代码,使用:

java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"

并使用命令行参数来启动 URLClassLoader一切正常。使用静态初始化程序,我确认这两个类已加载 URLClassLoader 的实例。 。 但是,如果我这样做,这就是问题所在:

java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"

无法加载 LoadedClassDep ( ClassNotFoundException )。 LoadedClass已正确加载,但带有 sun.misc.Launcher$AppClassLoader ,而不是 URLClassLoader ! 看起来,由于应用程序类加载器能够加载 LoadedClass它还尝试加载 LoadedClassDep ,忽略 URLClassLoader .

这是完整的源代码:

package example.bc; public class ClassloaderTest { public static void main(String[] args) { new ClassloaderTest().run(args); } private void run(String[] args) { URLClassLoader myClasLoader = initClassLoader(args); try { Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader); Object obj = cls.newInstance(); cls.getMethod("call").invoke(obj); } catch (Exception e) { e.printStackTrace(); } } private URLClassLoader initClassLoader(String[] args) { URL[] urls = new URL[args.length]; try { for (int i = 0; i < args.length; i++) { urls[i] = new File(args[i]).toURI().toURL(); } } catch (MalformedURLException e) { e.printStackTrace(); } return new URLClassLoader(urls, getClass().getClassLoader()); } } package com.example.bc; import com.bc.LoadedClassDep; public class LoadedClass { static { System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass()); } public void call() { new LoadedClassDep(); } } package com.bc; public class LoadedClassDep { static { System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass()); } }

我希望我已经说得足够清楚了。我的问题是,我只知道 ClassLoadeTest 的路径在编译时,我必须在运行时对其他路径使用字符串。那么,有什么想法可以让第二种情况发挥作用吗?

最佳答案

我希望应用程序类加载器在第二种情况下加载 LoadedClass,因为类加载器最初委托(delegate)给其父级 - 这是 standard behaviour 。在第二种情况下,LoadedClass 位于父级的类路径上,因此它会加载该类,而不是放弃并让 URLClassLoader 尝试。

然后,应用程序类加载器尝试加载 LoadedClassDep,因为它是在 LoadedClass 中直接导入和引用的:

public void call() {
    new LoadedClassDep();
}

如果需要在运行时动态且独立地加载这些类,则不能通过这种方式在它们之间进行直接引用。

也可以更改尝试类加载器的顺序 - 请参阅 Java classloaders: why search the parent classloader first?对此进行一些讨论。

关于java - 链式类加载器难题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9161133/

相关文章:

Java 并行流 - 调用 parallel() 方法的顺序

java - 包含具有相同签名的方法的多个接口(interface)

java - 框/表内的输入框

java - 从 Fragment 启动 Activity 抛出 ClassNotFoundException

java - 系统类加载器的名称

JavaFX 从选项卡获取元素

java - 在Elasticsearch中,如何在聚合级别应用过滤器

JavaHelp 的 Java newInstance 调用在第二次及后续调用时崩溃并出现 createUI 错误

Java:从内部类访问 protected 字段

java - WAR 共享的容器级版本化库