【发布时间】: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