Java RMI详解

来源:互联网 发布:我知女人心南宫寒正序 编辑:程序博客网 时间:2024/05/18 17:02

一丶RMI 定义
        RMI(Remote Method Invocation):远程方法调用。能够让某个 java 虚拟机上的对象调用运行在另一个 java 虚拟机上的对象的方法,就像调用本地方法一样。这两个虚拟机可以是运行在相同计算机上不同组件的不同进程中,也可以是运行在网络上不同计算机的当中,解决系统之间的通信问题。


二丶RMI调用时序图







三丶关于 RMI 的例子


客户端接口:

public interface HelloRmi extends Remote {    public String sayHello() throws RemoteException;}


接口实现:

public class HelloRmiImpl extends UnicastRemoteObject implements HelloRmi,Serializable {    public HelloRmiImpl() throws RemoteException {    }    public String sayHello() throws RemoteException {        return "Hello Rmi......";    }}

发布服务:

public class RmiServer {    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {        HelloRmi rmi = new HelloRmiImpl();        String url = publishService(rmi, "127.0.0.1", 1099);        System.out.println("rmi service has bean started......");    }    // 发布 RMI 服务    private static String publishService(Remote remote, String host, int port) {        String url = null;        try {            /**             * host 是注册表所在的主机(远程或本地)             * port 是注册表接受调用的端口号,默认为 1099             */            url = String.format("rmi://%s:%d/%s", host, port, remote.getClass().getName());            //创建并导出接受指定 port 请求的本地主机上的 Registry 实例            LocateRegistry.createRegistry(port);            // 将指定的名称 url 重新绑定到一个新的远程对象            Naming.rebind(url, remote);            System.out.println("publish rmi service,url: = " +  url);        } catch (RemoteException e) {            e.printStackTrace();        }catch (MalformedURLException e) {            e.printStackTrace();        }        return url;    }}

调用服务:

public class RmiClient {    public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException {        String url= "rmi://127.0.0.1:1099/com.lai.rmi.server.HelloRmiImpl";        //返回与指定名称 url 关联的远程对象的引用        HelloRmi rmi = (HelloRmi) Naming.lookup(url);        System.out.println(rmi.sayHello());    }}

四丶注意的细节


1丶因为方法的参数跟返回值最终都是会在网络上传输,所以实现必须是可序列化的

2丶UnicastRemoteObject类的构造函数抛出了RemoteException,故其继承类不能使用默认构造函数,继承类的构造函数必须也抛出RemoteException

3丶Registry 是简单远程对象注册表的一个远程接口,它提供存储和获取绑定了任意字符串名称的远程对象引用的方法

4丶Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口

5丶Skeleton(代理,学术名骨架)    Stub(代理):学术名存根。在服务端我们发布了RMI服务,并在JNDI中进行了注册,此时就在服务端创建了一个Skeleton,当客户端第一次成功连接JNDI并获取远程服务对象后,立马在本地创建了一个Stub

6丶远程通信实际是通过Skeleton与Stub来完成的,数据是基于TCP/IP协议


在服务端我们发布了RMI服务,并在JNDI中进行了注册,此时就在服务端创建了一个Skeleton(骨架),当客户端第一次成功连接JNDI并获取远程服务对象后,立马在本地创建了一个Stub(存根)