疯狂的类加载器问题

发布于 2024-09-15 00:11:59 字数 513 浏览 18 评论 0原文

类:

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

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

问题是,由于某种奇怪的原因,我必须使用 child ClassLoader 加载接口 Inter 并使用 Impl 加载实现类 Impl强>父类加载器。

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

有什么方法可以使用子 ClassLoader (上下文 ClassLoader)加载实现吗?或者我可能需要编写一些自定义类加载器来加载它们(通过打破委托规则)?

The classes:

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

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

The issue is that for some freaky reason, I have to load the interface Inter with child ClassLoader and the implementation class Impl with parent ClassLoader.

In this case I will get NoClassDefError, because the parent ClassLoader that is trying to load the implementation Impl doesn't know about the interface Inter that was loaded in child ClassLoader.

Is there any way of loading the implementation with child ClassLoader (context ClassLoader) ? Or may be I need to write some custom ClassLoader to load both of them (by breaking the delegation rule) ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

肥爪爪 2024-09-22 00:11:59

问题是对于一些怪异的人来说
原因,我必须加载界面
与子类加载器交互
具有父级的实现类 Impl
类加载器。

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

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

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

  • 父类优先:让父类加载器首先加载类。这通常是一种传递行为 - 大多数父类加载器将推迟加载到其父类,依此类推,直到到达类加载器层次结构中的引导类加载器(根)。如果父类加载器无法加载该类,则子类加载器会尝试加载该类。加载类的最终失败应该导致抛出 ClassNotFoundException。
  • Parent-last:自定义类加载器尝试先加载类,然后再委托给父类。仅当子类加载器尝试加载类失败时,才会使用父类加载器。

大多数类加载器都是作为父优先类加载器实现的。这是因为委托机制能够向上遍历树,但不能向下遍历树。

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

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

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

The issue is that for some freaky
reason, I have to load the interface
Inter with child ClassLoader and the
implementation class Impl with parent
ClassLoader.

I cannot fathom why the child classloader must load the interface, while leaving the parent classloader to load the implementation. This is bound to cause trouble, for there is no mechanism within the class-loading mechanism utilized by the JVM, to defer loading of classes to a child classloader. The usual mechanism of implementing the classloading behavior in the JVM is defined in the API documentation of the ClassLoader class:

The ClassLoader class uses a
delegation model to search for classes
and resources. Each instance of
ClassLoader has an associated parent
class loader. When requested to find a
class or resource, a ClassLoader
instance will delegate the search for
the class or resource to its parent
class loader before attempting to find
the class or resource itself. The
virtual machine's built-in class
loader, called the "bootstrap class
loader", does not itself have a parent
but may serve as the parent of a
ClassLoader instance.

One can write a custom classloader, by extending the ClassLoader class and overriding the loadClass() method. Extending this method allows to you to change the class loading delegation in either of the two ways:

  • Parent-first: Get the parent classloader to load the class first. This usually is a transitive behavior - most parent classloaders will defer loading to their parent, and so on, until the bootstrap classloader (the root) is reached in the classloader hierarchy. If the parent classloader fails to load the class, the child attempts to load it. An eventual failure in loading the class should result in a ClassNotFoundException being thrown.
  • Parent-last: The custom classloader attempts to load the class first, before delegating to the parent. The parent classloaders are used only when the child fails in its attempt to load the class.

Most classloaders are implemented as parent-first classloaders. This is due to the fact that the delegation mechanism is able to traverse the tree in the upward direction but not in the downward direction.

If you really wish to delegate loading and finding of classes to child classloaders in the hierarchy, you will have to manage references to them in the custom classloader for the parent. This is not easy, and is usually not done at all except for very exceptional circumstances since it very easy to end up with the dreaded ClassNotFoundException and NoClassDefFoundError as one must be careful to load only the required classes from the child classloaders, while the rest must always be deferred to the parent (unless I'm mistaken, the feature of shared libraries in certain Java EE containers are implemented this way).

Having said that, the ideal solution would be to attempt loading both the interface and the implementation classes in the parent classloader, and rely on the delegation mechanism to ensure that the classes are visible to both the classloaders; the parent can "see" classes loaded by itself, and the child can "see" the parent's classes.

PS: Don't forget to use AccessController.doPrivileged when loading and defining classes.

无声无音无过去 2024-09-22 00:11:59

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

我猜你做到了。

加载的默认行为首先加载父类文件,并将其标记为已加载的文件,如果找到,loadClass将首先加载已加载的类,这样我就可以重写并没有在自定义类加载器中调用super.loadClass方法。

Do you override the loadClass(String name,boolean resolve) of java.lang.ClassLoader?

I guest you did.

The default behaviour of loading loads the parent class file first,and marks it as loaded one,the loadClass will take loaded class first if found,that's way I guest you override and did not invoke super.loadClass method in customised class loader.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文