在另一台主机上运行RMIRegistry到RMIServers

时间:2010-10-28 01:28:51

标签: java rmi rmiregistry

这可能吗? (假设Java 6)

说明我的观点的一个人为/简单的例子是:

  • 我有一个定义明确的RMI接口永远不会改变(单个JAR文件,没有模板参数)
  • 在主机X上运行的RMIRegistry;
  • 来自主机Y的注册表.rebind()(主机X上的RMIRegistry)的RMI服务;和
  • 从主机Z执行RMI调用的RMI客户端

如果可能,我如何在RMI服务上指定属性“java.rmi.server.codebase”(主机Y上的进程)?

如果主机A和B是相同的机器,则当“java.rmi.server.codebase”为“file:/// C:/rmiCodebase/myCommonInterface.jar”时,此配置可以

如果主机A和B在单独的机器上,那么我在重新绑定上得到以下异常(在主机Y上设置相同的“java.rmi.server.codebase”):

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
java.lang.ClassNotFoundException: 

如果主机A和B在单独的机器上,我通过Web服务器使接口JAR可用(其中“java.rmi.server.codebase”是“http:// Y / rmiCodebase / myCommonInterface.jar“ OR ”http://Z/rmiCodebase/myCommonInterface.jar“),然后我在重新绑定上得到了这个稍微不同的错误:

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
java.rmi.AccessException: Registry.Registry.rebind disallowed; origin /10.0.190.25 (host Y) is non-local host

我有点困惑 - 如果所有RMI服务必须在与RMIRegistry相同的物理主机上运行(这是我成功完成工作的唯一方法),这似乎非常有限制。

在一天结束时,我只希望机器Z能够对在机器Y上运行的服务进行RMI调用。我将myCommonInterface.jar提供给在机器Y和Z上运行的进程。我不要甚至希望机器X必须对公共(远程)接口做任何事情!

虽然以下链接很有用,但我无法回答这个问题:http://download.oracle.com/javase/1.4.2/docs/guide/rmi/codebase.html

3 个答案:

答案 0 :(得分:0)

  

这可能吗?

不,不可能。请参阅Javadoc for Registry.bind()/ rebind()/ unbind()和Naming.bind()/ rebind()/ unbind()。

但是,您可以使用LDAP服务而不是RMI注册表。

  

我只想让机器Z能够   对正在运行的服务进行RMI调用   在机器Y

为什么这个问题呢?机器Z在机器Y上查找注册表有什么问题?

答案 1 :(得分:0)

不完全是一个具体的答案,但暗示限制:

http://download.oracle.com/javase/6/docs/api/java/rmi/registry/Registry.html

注册表实现可以选择限制对其部分或全部方法的访问(例如,修改注册表绑定的方法可能仅限于源自本地主机的调用)。如果Registry方法选择拒绝对给定调用的访问,则其实现可能会抛出AccessException,当由远程客户端捕获时,它会被包装在ServerException中(因为它扩展了RemoteException)。

答案 2 :(得分:0)

我的用例非常简单(基本上,使用RMI作为命令分布式系统的一种方式),但我能够避免一起使用注册表。

这是一个解决方法,我最终用于Map-Reduce-miniframework。

在:

In client:    
    remoteMaster = (Master) remoteRegistry.lookup("master");
    // Add self to remote registry (BAD!)
    Worker stub = (Worker) UnicastRemoteObject.exportObject(this, 15213);
    remoteMaster.bind("workerName", stub);

后:

(在此变通方法中,我们将手动保存RemoteObject,而不是使用注册表)

In Master:
     List<Worker> workers = new List<Worker>();

     public void registerWorker(String name, Worker stub) throws RemoteException {
          worker.add(stub);
      }

保存远程实例后,您可以传递它并像调用任何其他对象一样调用它。

注意这种方法只有在你只使用注册表作为临时存储位置(我是)时才有用,因为你只是通过不将它添加到注册表来避免“访问限制”,并保留它本地。

只需记录我的(略微hacky)解决方案,欢迎评论。