【问题标题】:Unloading classes passed via RMI卸载通过 RMI 传递的类
【发布时间】:2010-08-29 13:35:17
【问题描述】:

我有一个简单的 RMI“计算”服务器应用程序(类似于 this),它通过 RMI 从客户端接受某种接口类型的对象,执行接收对象的 compute() 方法,并通过 RMI 将结果返回给远程客户端。这些作业是“一次性的”,不同作业之间或不同作业的对象之间没有交互。

我希望能够修改类并将实例提交到计算服务器以供执行,而无需不断重新启动服务器 JVM。但是,当已修改的类作为参数再次提交给远程调用时,它的方法行为不会改变(匿名类也会发生这种情况)。我一直在阅读有关序列化的信息,我意识到这与 ClassLoader 无法修改现有类有关。

从我对 SO 和其他地方的阅读中,我意识到加载流类的 ClassLoader 必须以某种方式被 GC 和替换,以便加载我的类的新版本。我知道如何做到这一点,但由于底层 RMI 运行时和它有自己的 RMIClassloader,情况似乎很复杂。

我的问题是:加载通过 RMI 参数接收的类的每个新版本的最简单方法是什么。理想情况下,我正在寻找一种方法让每个远程调用都获得一个新的 ClassLoader 并在返回时处理它。如果没有定制类加载器和 RMI 内部的复杂知识,这是否可行?

欢迎任何指向阅读材料或示例的指针!

编辑:这是计算服务器的远程接口:

public interface ComputationEngine extends Remote {
    public Object execute(Task t) throws RemoteException;
}

还有“计算作业”界面Task

public interface Task extends java.io.Serializable {
    public Object compute();
}

【问题讨论】:

  • 这不是类加载器需要被 GC (尽管如果不是,你最终会耗尽内存)。 IIRC,在 RMI 实现的一部分中,有一个从代码库到 ClassLoader 的映射。
  • compute() 的参数是什么?客户端是在发送他们想要执行的类文件,还是只是在出现错误时尝试动态更新 compute() 接口的实现,而无需重新启动服务器?
  • @Tom:我的印象是卸载类的唯一方法是 GC ClassLoader。从我的实验看来,所有远程调用都使用相同的ClassLoader。不过谢谢,我会使用这些术语进行更多搜索。
  • @bkail:客户端正在发送自定义类的对象(实现Task)以供执行。我希望能够修改/调整客户端“作业”类的方法代码,重新提交作业,然后能够在不重新启动服务器 JVM 的情况下观察新行为。谢谢:-)
  • A ClassLoader 及其类将同时被收集。如果它们由不同的类加载实例加载,您可能会错过多个具有相同完全限定名称的类。 (顺便说一句,“@”和用户名之间应该没有通知才能起作用。)

标签: java rmi classloader


【解决方案1】:

唯一的方法是当你想改变一个类时有一个新的类加载器。 如何使用 URLClassLoader 并从 URL 中获取代码

我在我的一个项目中使用它来在 jar 文件更改时更新 API。看看这里: http://code.google.com/p/open-forum/source/browse/trunk/Wiki/org/one/stone/soup/wiki/jar/manager/JarManager.java 184+行

检查您的电子邮件:-)

【讨论】:

    【解决方案2】:

    这并不能真正回答您的问题,但可以将您的部分类更改为数据而不是实际类。使用Map 而不是字段等。你的类会少很多,而且你的代码也可能更简单。

    【讨论】:

    • 它是一个通用计算服务器(如 RMI 的 Java 教程中所示)。当需要更改字节码指令的代码时,弄乱数据将无济于事。
    • 感谢您的想法,就像汤姆说的那样,尽管我依赖于更新发送到服务器的类的 行为(即方法代码)(我已将问题更新为让它更清楚)。
    猜你喜欢
    • 1970-01-01
    • 2015-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 2018-11-14
    • 1970-01-01
    • 2011-12-03
    相关资源
    最近更新 更多