Domanda

Ho due applicazioni che comunicano tramite RMI, un server slave (di cui non ci sarà più) e di un server master.

A seguito di un buon disegno astratto, vorrei implementare lo schiavo in un modo che non sa che quando si parla al master, che sta utilizzando RMI (in modo che le due applicazioni possono essere eseguiti anche all'interno della stessa JVM, per esempio):

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

...

class Slave {

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

}

Problema: La marcata PROBLEM LINE linea di cui sopra non funziona, perché non posso semplicemente passare questo (il Slave è di per sé un Remote che Master parlerà di nuovo a). Devo fare in modo esplicito un UnicastRemoteObject.exportObject(this, 0) (o toStub(this) se è esportato in precedenza), ma che rende la classe Slave dipendono RMI, rompendo il design.

Inoltre, registerSlave mi costringe a RemoteException cattura, che aggiunge anche RMI dipendenza.

Cosa suggeriresti per risolvere questi problemi?

(mi ha anche bug che queste classi devono implementare a distanza, ma credo che possiamo solo andare così lontano con l'astrazione)

È stato utile?

Soluzione

Bene, ho fatto in questo modo:

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);
   }
  }
}

Altri suggerimenti

  

RMI ha bisogno esplicito di esportazione   oggetti

Solo se non si estendono UnicastRemoteObject o attivabile. Se lo fanno sono auto-esportato per la costruzione.

  

che devo fare in modo esplicito un   UnicastRemoteObject.exportObject (questo,   0)

No, vedi sopra.

  

(o toStub (questo) se è esportato   in precedenza)

Qualunque sia toStub () è. C'è un RemoteObject.toStub (), ma non può essere chiamata che, e se siete stai perdendo il tuo tempo.

Ma non c'è bisogno di farlo a tutti. Se 'questo' è un oggetto remoto esportato si può semplicemente passare intorno come parametro di RMI o il risultato. RMI sostituirà automaticamente lo stub.

sarei diffidare di questa astrazione - richieste gestite da remoto sono diverse dalle richieste gestite a livello locale in molti modi -. Latenza, modalità di guasto, la semantica di tentativi

Potrebbe essere che il vostro astrazione è che perde perché non è davvero valido.

Una certa parte della vostra applicazione Schiavo sta per essere pronti a ricevere chiamate tramite RMI, e trattare con RemoteException, ecc Perché non introdurre un proxy di qualche tipo tra slave e master che media la comunicazione e si nasconde il RMI vs questione locale. Ad esempio, lungo le linee di:

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);
   }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top