在Java中卸载类?

我有一个自定义的类加载器,以便桌面应用程序可以dynamic地从我需要与之交谈的AppServer加载类。 我们这样做是因为要做到这一点的jar子的数量是荒谬的(如果我们想运送它们)。 如果我们不在运行时从AppServer库dynamic加载类,我们也有版本问题。

现在,我只是遇到了一个问题,我需要和两个不同的AppServer对话,并发现首先加载的类可能会坏掉。有没有办法强制卸载这个类,而不是真的杀死JVM?

希望这是有道理的

一个类可以被卸载的唯一方法是如果使用的类加载器被垃圾收集。 这意味着,引用每一个类和类加载器本身都需要去渡​​渡鸟。

一个可能的解决scheme是为每个jar文件提供一个Classloader,并为每个AppServers提供一个Classloader,将实际的类加载委托给特定的Jar类加载器。 这样,您可以为每个App服务器指向不同版本的jar文件。

但这并不是微不足道的。 OSGi平台努力做到这一点,因为每个bundle都有一个不同的类加载器,依赖关系由平台解决。 也许一个好的解决办法是看看它。

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

并创build一个扩展Classloader的新的MultiClassloader类。 这个类内部会有一个JarClassloaders的数组(或List),并且在defineClass()方法中迭代所有的内部类加载器,直到find一个定义或抛出一个NoClassDefFoundException。 可以提供一些访问器方法来为类添加新的JarClassloaders。 在MultiClassLoader的networking上有几个可能的实现,所以你可能甚至不需要写自己的。

如果您为服务器的每个连接创build一个MultiClassloader,原则上每个服务器都可能使用同一个类的不同版本。

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

是的,有办法加载类,并在稍后“卸载”。 诀窍是实现您自己的类加载器,它位于高级类加载器(System类加载器)和应用程序服务器的类加载器之间,并希望应用程序服务器的类加载器将类加载委托给上加载器。

一个类是由它的包,它的名字和它最初加载的类加载器来定义的。 编写一个“代理”类加载器,这是启动JVM时加载的第一个类。 工作stream程:

  • 程序启动,并通过这个代理类加载器加载真正的“主”类。
  • 然后通常加载的每个类(即不通过另一个会破坏层次结构的类加载器实现)将被委派给这个类加载器。
  • 代理类加载器将java.xsun.x委托给系统类加载器(不能通过除系统类加载器以外的其他类加载器加载)。
  • 对于每一个可replace的类,实例化一个类加载器(它真的加载了类,并且不把它委托给父类加载器),并通过它加载它。
  • 将类的包/名称作为键和类加载器存储为数据结构(即Hashmap)中的值。
  • 每次代理类加载器都获得之前加载的类的请求时,它将从之前存储的类加载器中返回类。
  • 通过类加载器(或者从数据结构中“删除”键/值对)来定位类的字节数组就足够了,并且在需要修改的时候重新加载类。

在那里做不应该有一个ClassCastException或LinkageError等

有关类加载器层次结构的更多信息(是的,这正是你在这里实现的; – )看Ted Neward的“基于服务器的Java编程” – 那本书帮助我实现了与你想要的非常相似的东西。

我写了一个自定义类加载器,从中可以卸载单个类,而不需要GC加载类加载器。 Jar类装载机

类加载器可能是一个棘手的问题。 如果您使用多个类加载器,并且没有明确和严格地定义它们的交互,则尤其会遇到问题。 我想为了实际上能够卸载一个类,你将不得不删除所有你想要卸载的类(及其实例)的引用。

大多数人需要做这种types的事情最终使用OSGi 。 OSGi是真正强大和令人惊讶的轻量级和易于使用,

您可以卸载ClassLoader,但不能卸载特定的类。 更具体地说,你不能卸载ClassLoader中不受你控制的类。

如果可能的话,我build议使用自己的ClassLoader,以便卸载。

类对其ClassLoader实例有一个隐含的强引用,反之亦然。 与Java对象一样,它们被垃圾收集。 如果没有敲击工具界面或类似的东西,你不能删除单个类。

一如既往,你可以得到内存泄漏。 任何对您的类或类加载器的强引用都会泄漏整个事物。 例如,ThreadLocal,java.sql.DriverManager和java.beans的Sun实现会发生这种情况。

如果您正在观看卸载类是否在JConsole中工作,请尝试在类卸载逻辑末尾添加java.lang.System.gc() 。 它显式触发垃圾收集器。