回调方法
在客户端实例化一个远程( Remote )对象,调用远程方法时作为 参数 传递给服务端,服务端通过调用这个远程对象的方法实现回调。
在客户端编写一个供回调远程接口,这次叫ICallback,而非IMethod。
import Java .rmi.Remote; import java.rmi.RemoteException; public interface ICallback extends Remote { //供服务端调用,同样 code 参数用于标识两台 void callback(int code) throws RemoteException; }
同样的 extends UnicastRemoteObject implements I callback
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class CallbackImpl extends UnicastRemoteObject implements ICallback {
protected CallbackImpl() throws RemoteException {
}
@ Override
public void callback(int code) throws RemoteException {
System.out.println("From " + code + " : Roger that.");
}
}
修改之前的接口
增加一个方法call(ICallback callback)
import java.rmi.Remote; import java.rmi.RemoteException; public interface IMethod extends Remote { void sayHi(int code) throws RemoteException; void call(ICallback callback) throws RemoteException; }
同时在服务端修改实现类
... ...
@Override
public void call(ICallback callback) throws RemoteException {
System.out.println("From Client" + " : Hello");
callback.callback( Runtime .getRuntime().hashCode());
}
... ...
客户端调用远程方法
//实例化回调对象
ICallback callback = new CallbackImpl();
//调用远程方法
method.call(callback);
//回收回调对象
UnicastRemoteObject.unexportObject(callback, false);
可以看到,我们新建了一个远程对象ICallback,并在客户端实现了它。将其作为参数,传递到远程对象的IMethod的call方法。而IMethod的实现则是在服务端完成的。即是,在客户端调用了服务端的call()方法,而服务端则调用了客户端的callback()方法。
运行
同样,先运行起服务端,再运行客户端
可以在服务端的控制台看见输出
From Client : Hello
在客户端的控制台看见输出
From 服务端hashCode : Roger that.
说明客户端调用了服务端的call方法,服务端在call方法中调用了客户端传递过来的callback对象的callback方法,并传递过去了本地Runtime的hashCode。
常见的问题
抛出异常
java .rmi.server.ExportException: remote object implements illegal remote interface;
原因:Remote接口中声明的方法必须声明throws RemoteException
java.rmi.server.ExportExcept io n: internal error: ObjID already in use
原因:端口被占用或重复在同一端口号创建远程对象注册表
java.net.MalformedURLException: invalid URL scheme
原因:绑定远程对象时的name字符串必须符合URL格式,且前面的协议名必须为rmi://或者省略
程序不能正常结束
需要回收导出的远程对象,调用UnicastRemoteObject类的方法unexportObject(Remote obj, boolean force)
//回收远程对象
UnicastRemoteObject.unexportObject(object, false);
另外,上文编写远程接口实现类时,可以不使用extends扩展自UnicastRemoteObject。
那么这时候要求这个实现类实现可 序列化 接口Serializable,并且在绑定端口时通过调用UnicastRemoteObject类的exportObject方法获取这个远程对象的代理对象,再调用Naming.bind进行绑定。
import java.io.Serializable;
import java.rmi.RemoteException;
public class MethodImpl implements IMethod, Serializable {
protected MethodImpl() throws RemoteException {
}
//实例化远程对象
IMethod method = new MethodImpl();
//获取代理对象
Remote obj = UnicastRemoteObject.exportObject(method, 10086);
//绑定端口
Naming.bind("// localhost :10086/method", obj);