疯狂的ClassLoader问题

时间:2010-08-18 07:33:37

标签: java classloader contextclassloader

课程:

public interface Inter {
  ...some methods...
}

public class Impl implements Inter {
  ...some implementations...
}

问题在于,出于某种原因,我必须使用 ClassLoader加载接口Inter,并使用 parent Impl > ClassLoader。

在这种情况下,我将获得NoClassDefError,因为尝试加载实现Impl的父ClassLoader不知道子类ClassLoader中加载的接口Inter

有没有办法用子ClassLoader(context ClassLoader)加载实现?或者我可能需要编写一些自定义的ClassLoader来加载它们(通过破坏委托规则)?

2 个答案:

答案 0 :(得分:3)

  

问题是对于一些怪异的人   原因,我必须加载界面   与孩子ClassLoader和   实现类Impl与父级   类加载器。

我无法理解为什么子类加载器必须加载接口,同时让父类加载器加载实现。这肯定会造成麻烦,因为在JVM使用的类加载机制中没有机制来将类加载到子类加载器。在JVM中实现类加载行为的常用机制在ClassLoader类的API文档中定义:

  

ClassLoader类使用a   委托模型来搜索类   和资源。每个实例   ClassLoader具有关联的父级   类加载器。当要求找到一个   类或资源,ClassLoader   实例将委托搜索   其父级的类或资源   尝试查找之前的类加载器   类或资源本身。该   虚拟机的内置类   loader,称为“bootstrap类   loader“,本身并没有父母   但可以作为一个的父母   ClassLoader实例。

可以通过扩展ClassLoader class并覆盖loadClass() method来编写自定义类加载器。扩展此方法允许您以两种方式之一更改类加载委派:

  • Parent-first :获取父类加载器以首先加载该类。这通常是一种传递行为 - 大多数父类加载器会将加载推迟到其父级,依此类推,直到在类加载器层次结构中到达引导类加载器(根)。如果父类加载器无法加载类,则子进程尝试加载它。加载类时最终失败应该导致抛出ClassNotFoundException。
  • Parent-last :在委托给父级之前,自定义类装入器首先尝试加载该类。仅当子项尝试加载类失败时才使用父类加载器。

大多数类加载器都是作为父级优先级的类加载器实现的。这是因为委托机制能够向上移动树而不是向下移动。

如果您真的希望将类的加载和查找委托给层次结构中的子类加载器,则必须在父类的自定义类加载器中管理对它们的引用。这并不容易,并且除了非常特殊的情况之外通常都没有完成,因为它很容易以可怕的ClassNotFoundException和NoClassDefFoundError结束,因为必须小心只从子类加载器加载所需的类,而其余必须总是被推迟到父级(除非我弄错了,某些Java EE容器中的共享库的功能是以这种方式实现的。)

话虽如此,理想的解决方案是尝试在父类加载器中加载接口和实现类,并依赖委托机制来确保类对两个类加载器都可见;父母可以“看到”自己加载的类,孩子可以“看到”父母的类。

PS:加载和定义类时不要忘记使用AccessController.doPrivileged

答案 1 :(得分:0)

你是否覆盖了java.lang.ClassLoader的loadClass(String name,boolean resolve)?

我邀请你做过。

加载的默认行为首先加载父类文件,并将其标记为已加载的文件,如果找到,loadClass将首先获取加载的类,这是我重写的guest用户的方式,并且没有在自定义的类加载器中调用super.loadClass方法