problema di progettazione: RMI ha bisogno esplicito di esportazione di oggetti
-
02-10-2019 - |
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)
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);
}
}