设计问题:RMI需要明确导出对象
-
02-10-2019 - |
题
我有两个通过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依赖性。
您建议解决这些问题?
(这也让我感到困扰,这些类必须实现远程,但我想我们只能通过抽象走得那么远)
解决方案
好吧,我这样做了:
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或可激活。如果他们这样做,他们将在施工中自动出口。
我必须明确执行UnicastremoteObject.exportObject(this,0)
不,请参见上文。
(或Tostub(此)如果之前出口)
无论tostub()是什么。有一个RemoteObject.tostub(),但是您不能打电话给它,如果您正在浪费时间。
但是您根本不必这样做。如果“此”是导出的远程对象,则可以将其作为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);
}
}