Проблема проектирования: RMI нуждается в явном экспорте объектов
У меня есть два приложения, взаимодействующих через 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
сам по себе Remote
который Master
поговорим) Я должен явно сделать UnicastRemoteObject.exportObject(this, 0)
(или же toStub(this)
если он экспортируется ранее), но это делает Slave
класс зависит от RMI, ломая дизайн.
Дополнительно, registerSlave
заставляет меня ловить RemoteException
, который также добавляет зависимость RMI.
Что бы вы предложили для решения этих проблем?
(Мне также жаль, что эти классы должны реализовывать Remote, но я думаю, что мы можем зайти так далеко с абстракцией)
4 ответа
Ну, я сделал это так:
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);
}
}
}
RMI нуждается в явном экспорте объектов
Только если они не расширяют UnicastRemoteObject или Activatable. Если они это делают, они автоматически экспортируются на стройке.
Я должен явно сделать UnicastRemoteObject.exportObject(это, 0)
Нет, смотри выше.
(или toStub(this), если он экспортирован ранее)
Какой бы ни была функция toStub(). Есть RemoteObject.toStub(), но вы не можете так его называть, и если вы это делаете, вы тратите время впустую.
Но вам не нужно этого делать вообще. Если 'this' является экспортированным удаленным объектом, вы можете просто передать его как параметр или результат RMI. RMI заменит заглушку автоматически.
Я бы с осторожностью отнесся к этой абстракции - удаленно обслуживаемые запросы во многом отличаются от локально обслуживаемых - задержка, режимы сбоев, семантика повторных попыток.
Может случиться так, что ваша абстракция утечка, потому что она не действительно действительна.
Некоторая часть вашего ведомого приложения должна быть готова к приему вызова через RMI и работе с RemoteException и т. Д. Почему бы не ввести какой-либо прокси-сервер между подчиненным и ведущим, который опосредует связь и скрывает 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);
}
}