在java中卸载类?

2022-08-31 06:35:40

我有一个自定义类装入器,以便桌面应用程序可以从我需要与之通信的应用程序服务器动态地开始加载类。我们这样做是因为这样做所需的罐子数量是荒谬的(如果我们想运送它们)。如果我们不在运行时从 AppServer 库动态加载类,我们也会遇到版本问题。

现在,我刚刚遇到了一个问题,我需要与两个不同的应用程序服务器交谈,并发现根据我首先加载的类,我可能会严重中断...有没有办法在不实际杀死JVM的情况下强制卸载类?

希望这是有道理的


答案 1

卸载类的唯一方法是使用垃圾回收的类装入器。这意味着,对每个类和类加载器本身的引用都需要走渡渡鸟的道路。

问题的一个可能的解决方案是为每个 jar 文件设置一个类加载器,为每个 AppServer 设置一个类加载器,它将类的实际加载委托给特定的 Jar 类加载器。这样,您可以为每个应用服务器指向 jar 文件的不同版本。

不过,这并非微不足道。OSGi 平台努力做到这一点,因为每个捆绑包都有一个不同的类装入器,并且依赖关系由平台解析。也许一个好的解决方案是看看它。

如果您不想使用 OSGI,一种可能的实现可能是为每个 JAR 文件使用一个 JarClassloader 类实例。

并创建一个新的多类装入器类,用于扩展类装入器。这个类在内部将有一个 JarClassloaders 数组(或 List),在 defineClass() 方法中将循环访问所有内部类加载器,直到可以找到一个定义,或者抛出一个 NoClassDefFoundException。可以提供几个访问器方法来向类中添加新的 JarClassloaders。对于 MultiClassLoader,网络上有几种可能的实现,因此您甚至可能不需要编写自己的实现。

如果为与服务器的每个连接实例化多类装入器,原则上每个服务器都可能使用同一类的不同版本。

我在一个项目中使用了MultiClassloader的想法,其中包含用户定义脚本的类必须从内存中加载和卸载,并且效果很好。


答案 2

是的,有一些方法可以加载类并在以后“卸载”它们。诀窍是实现你自己的类装入器,它位于高级类装入器(System 类装入器)和应用服务器的类装入器之间,并希望应用服务器的类装入器确实将类装入委托给上层装入器。

类由其包、名称和最初装入的类装入器定义。对“代理”类装入器进行编程,这是启动 JVM 时装入的第一个类装入器。工作流程:

  • 程序启动,真正的“main”类由此代理类装入器装入。
  • 然后,通常加载的每个类(即不通过另一个可能破坏层次结构的类加载器实现)将被委托给该类加载器。
  • 代理类装入器委托和系统类装入器(这些类装入器不得通过除系统类装入器以外的任何其他类装入器装入)。java.xsun.x
  • 对于每个可替换的类,实例化一个类装入器(它实际装入类,而不是将其委托给父类装入器)并通过此来装入它。
  • 将类的包/名称存储为键,将类装入器存储为数据结构(即Hashmap)中的值。
  • 每次代理类装入器收到对之前装入的类的请求时,它都会从之前存储的类装入器中返回该类。
  • 通过类装入器找到类的字节数组(或从数据结构中“删除”键/值对)并重新装入类以备更改它就足够了。

在那里完成不应该出现ClassCastExceptionLinkicleError等。

有关类装入器层次结构的更多信息(是的,这正是您在此处实现的内容;- )请查看Ted Neward的“基于服务器的Java编程” - 该书帮助我实现了与您想要的非常相似的东西。


推荐