RMI(即Remote Method Invoke 远程方法调用)。在Java中,只要一个类extends了java.rmi.Remote接口,即可成为存在于服务器端的远程对象,供客户端访问并提供一定的服务
以下内容是参考java API文档和自己实地代码测试的结果!!!
写接口
接口均要继承java.rmi. Remote接口。
Remote
接口用于标识其方法可以从非本地虚拟机上调用的接口。任何远程对象都必须直接或间接实现此接口。只有在“远程接口”(扩展 java.rmi.Remote
的接口)中指定的这些方法才可远程使用。
实现类可以实现任意数量的远程接口,并且可以扩展其他远程实现类。RMI 提供一些远程对象实现可以扩展的有用类,这些类便于远程对象创建。这些类是java.rmi.server.UnicastRemoteObject
和 java.rmi.activation.Activatable
。
注意:extends了Remote接口的类或者其他接口中的方法必须要声明抛出RemoteException异常,该才方法可被客户端远程访问调用。
例:
import java.rmi.Remote;
importjava.rmi.RemoteException;
publicinterface IRemoteService extends Remote{
String extract(String str) throws RemoteException;
}
写实现类
实现类除了要实现自定义的接口还要java.rmi.server.UniCastRemoteObject类(这是必须的)。因为这样才能保证客户端访问获得远程对象时,该远程对象将会把自身的一个拷贝以Socket的形式传输给客户端,此时客户端所获得的这个拷贝称为“存根”,而服务器端本身已存在的远程对象则称之为“骨架”。其实此时的存根是客户端的一个代理,用于与服务器端的通信,而骨架也可认为是服务器端的一个代理,用于接收客户端的请求之后调用远程方法来响应客户端的请求。
例:
importjava.rmi.RemoteException;
importjava.rmi.server.UnicastRemoteObject;
publicclass RemoteServiceIml
extends UnicastRemoteObject
implements IRemoteService{
protected RemoteServiceIml() throws RemoteException {
super();
}
@Override
public String extract(String filePath) {
System.err.println("extract执行了");
return"extract方法返回";
}
}
实现类方法可抛异常也可不抛
写服务端
java.rmi.registry. Registry是简单远程对象注册表的一个远程接口,它提供存储和获取绑定了任意字符串名称的远程对象引用的方法。bind
、unbind
和 rebind
方法用于改变注册表中的名称绑定,lookup
和 list
方法用于查询当前的名称绑定。
在其典型用法中,Registry
启用 RMI 客户机引导:它为客户机提供获得对远程对象的初始引用的简单方式。因此,导出的注册表的远程对象实现通常具有已知的地址,如具有已知的ObjID
和 TCP 端口号(默认为 1099
)。
Registry
实现可以选择限制对其中的某些或全部方法的访问(例如,可以限制改变注册表绑定的方法来限制对本地主机发起的调用)。如果Registry
方法选择拒绝对给定调用的访问,则其实现可能抛出AccessException
,抛出的这一异常(因为它扩展RemoteException
)可能会在远程客户端捕获它时包装在ServerException
中。
在 Registry
中用于绑定的名称是纯字符串,不是经过分析的。在Registry
中存储其远程引用的服务可能希望将包名称用作名称绑定中的前缀,以减少注册表中可能的名称冲突。
方法摘要 | |
void | bind(String name, Remote obj) 绑定对此注册表中指定 name 的远程引用。 |
String[] | list() 返回在此注册表中绑定的名称的数组。 |
Remote | lookup(String name) |
void | rebind(String name, Remote obj) |
void | unbind(String name) |
java.rmi.registry. LocateRegistry用于获得对特定主机(包括本地主机)上引导远程对象注册表的引用,或用于创建一个接受对特定端口调用的远程对象注册表。
注意,getRegistry
调用并不实际生成到远程主机的连接。它只创建对远程注册表的本地引用,即便远程主机上没有正运行的注册表,它也会成功创建一个引用。因此,调用作为此方法的结果返回的远程注册表的后续方法可能会失败。
方法摘要 | |
static Registry | createRegistry(int port) |
static Registry | createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) 在本地主机上创建并导出 Registry 实例,该本地主机使用的是与该实例通信的自定义套接字工厂。 |
static Registry | getRegistry() 返回本地主机在默认注册表端口 1099 上对远程对象 Registry 的引用。 |
static Registry | getRegistry(int port) |
static Registry | getRegistry(String host) 返回指定 host 在默认注册表端口 1099 上对远程对象 Registry 的引用。 |
static Registry | getRegistry(String host, int port) |
static Registry | getRegistry(String host, int port, RMIClientSocketFactory csf) 返回本地创建的指定 host 和 port 上对远程对象 Registry 的远程引用。 |
例:
importjava.rmi.RemoteException;
importjava.rmi.registry.LocateRegistry;
importjava.rmi.registry.Registry;
publicclass T {
publicstaticvoid main(String[] args) {
// 注册管理器
Registry registry = null;
try {
// 创建一个服务注册管理器
registry = LocateRegistry.createRegistry(8088);
} catch (RemoteException e) {
e.printStackTrace();
}
try {
// 创建一个服务
RemoteServiceIml remoteService =
new RemoteServiceIml();
// 将服务绑定命名
registry.rebind("remoteService", remoteService);
System.out.println("bind remoteService");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
写客户端
客户端所用类和服务端一样,仅仅方法不一样。
例:
importjava.rmi.AccessException;
importjava.rmi.NotBoundException;
importjava.rmi.RemoteException;
importjava.rmi.registry.LocateRegistry;
importjava.rmi.registry.Registry;
publicclass C {
publicstaticvoidmain(String[] args) {
// 注册管理器
Registry registry = null;
try {
// 获取服务注册管理器
registry = LocateRegistry.getRegistry("127.0.0.1",8088);
// 列出所有注册的服务
String[] list =registry.list();
for(String s : list){
System.out.println(s);
}
} catch (RemoteException e) {
}
try {
// 根据命名获取服务
IRemoteService remoteService =(IRemoteService) registry.lookup("remoteService");
// 调用远程方法
String result =remoteService.excavate(null, null) ;
// 输出调用结果
System.out.println("result from remote : " + result);
} catch (AccessException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}