【问题标题】:Design issue: RMI needs explicit exporting of objects设计问题:RMI 需要显式导出对象
【发布时间】:2011-04-12 16:41:54
【问题描述】:

我有两个通过 RMI 通信的应用程序,一个从属服务器(其中会有多个)和一个主服务器。

遵循良好的抽象设计,我想以一种方式实现从站,它不知道在与主站交谈时,它正在使用 RMI(这样两个应用程序也可以在同一个 JVM 中运行,例如):

public static void main(String[] a) {
     Master ms = magicGetTheMasterFromRMI();
     new Slave(ms);
}

...

class Slave {

   public Slave(Master m) {
       m.registerSlave(this); // PROBLEM LINE   
   }

}

问题:上面标记为PROBLEM LINE 的行不起作用,因为我不能简单地通过它(Slave 本身就是RemoteMaster 会回复它)。我必须明确地做一个UnicastRemoteObject.exportObject(this, 0)(或者toStub(this),如果它是之前导出的)但是这使得Slave类依赖于RMI,破坏了设计。

另外,registerSlave 强制我捕获 RemoteException,这也增加了 RMI 依赖。

您建议如何解决这些问题?

(这些类必须实现 Remote 也让我很困扰,但我想我们只能在抽象方面走这么远)

【问题讨论】:

    标签: java oop rmi abstraction leaky-abstraction


    【解决方案1】:

    RMI 需要显式导出 对象

    仅当它们不扩展 UnicastRemoteObject 或 Activatable 时。如果他们这样做,他们会在施工时自动导出。

    我必须明确地做一个 UnicastRemoteObject.exportObject(这个, 0)

    不,见上文。

    (或 toStub(this) 如果它被导出 早)

    无论 toStub() 是什么。有一个 RemoteObject.toStub(),但你不能调用它,如果你是在浪费你的时间。

    但您根本不必这样做。如果“this”是一个导出的远程对象,您可以将它作为 RMI 参数或结果传递。 RMI 将自动替换存根。

    【讨论】:

    • this 不是导出对象,而是源 Remote 对象。不过,我会调查你答案的第一部分。
    【解决方案2】:

    Slave 应用程序的某些部分必须准备好通过 RMI 接收呼叫,并处理 RemoteException 等。为什么不在 Slave 和 Master 之间引入某种代理来调解通信并隐藏 RMI与本地问题。例如,大致如下:

    public Slave(Master m)
    {
       new MasterConnection(m, this);
    }
    
    class MasterConnection implements Slave extends UnicastRemoteObject
    {
       Slave s;
    
       public MasterConnection(Master m, Slave s) throws IOException
       {
          this.slave = s;
          try {
             exportObject(this);
          } catch (RemoteException e){
             throw new IOException("Could not communicate with Master etc....");
          }
          master.registerSlave(this);
       }
    
       public void callbackFromMaster(Object arg) // or whatever
       {
          s.callbackFromMaster(arg);
       }
    }
    

    【讨论】:

      【解决方案3】:

      嗯,我是这样做的:

      interface Service {
         void doIt();
      }
      
      class ServiceImpl implements Service {
        public void doIt() { ... }
      }
      
      interface RemoteService extends Remote {
        void proxyDoIt() throws RemoteException;
      }
      
      class RemoteServiceHost implements RemoteService {
        public void proxyDoIt() throws RemoteException {
          // serviceImpl is a field, defined in the constructor
          serviceImpl.doIt();
        }
      }
      
      class RemoteServiceClient implements Service {
        public void doIt() {
         try {
          // remoteService is a field, defined in the constructor
          remoteService.proxyDoIt();
         } catch (RemoteException e) {
          throw new RuntimeException(e);
         }
        }
      }
      

      【讨论】:

        【解决方案4】:

        我会警惕这种抽象——远程服务的请求在很多方面与本地服务的请求不同——延迟、故障模式、重试语义。

        可能是您的抽象存在漏洞,因为它不是真正有效的。

        【讨论】:

        • 感谢您的评论,我会记住的。我个人觉得有漏洞的抽象总比没有抽象好,只要你知道漏洞。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-27
        • 2010-10-04
        相关资源
        最近更新 更多