Java RMI 远程方法调用 基础

17 篇文章 1 订阅

目录:

一、简介

二、RIMI 相关类系统了解

三、RMI 基础实践

四、RMI 与 Spring 实践


一、简介

RMI:Remote Method Invocation(远程方法调用),允许程序调用虚拟机中另一个进程(服务)方法或远程主机上的某个进程(服务)的方法。它是EJB的基础。

RPC:Remote Procedure Call Protocol(远程过程调用协议),和RMI 类似,区别主要有两点:

1、调用方式的差异。RMI 是通过签名(即远程服务类注册时所绑定的访问名称)访问的,而RPC 不需要绑定,是通过类似"类名.方法名"的形式调用的,当匹配到类名与方法名后,即调用执行;

2、适用范围的不同。RMI 是java 语言的一部分,只适用于java 的应用程序。RPC 支持多语言。

上面的理解可能有误,也可理解为RPC 是泛指远程调用框架,RMI 是其Java 语言的实现。一些PRC 框架:RMI 、Hessian、Dubbo。


二、RMI 相关类系统了解


首先看下相关包与类:java.rmi 包

java.rmi.activation包:java1.2起,为远程对象的激活提供支持,即使远程对象的访问是持久的(暂时不作多了解);

java.rmi.dgc包:DGC(distribution garbage collection)类,用于垃圾传送集合算法的服务端;Lease类,请求并授予契约给远程对象,里面包含了VM标识符与契约时间;VMID,虚拟机独特ID。所以此包主要定义了远程访问的时间。

java.rmi.server包:里面我们只关注几个类:RemoteObject 与 RemoteServer抽象类、UnicastRemoteObject 类。

java.registry包:绑定服务相关的类。



从编程步骤理解几个主要的类:

1、Remote 接口(远程服务)

定义远程对象类,即定义我们的远程服务类。

继承关系:UnicastRemoteObject实现类——>继承RemoteServer抽象类——>继承RemoteObject抽象类(实现了Serilazible接口)——>实现了Remote接口(空接口)。

远程对象类(服务类)都需继承Remote 的实现类,常用UnicastRemoteObject 类,但具体的业务逻辑可单独定义在实现了Remote 的接口中(必须直接或间接实现Remote),并在自己的服务类中实现自己的服务接口。

UnicastRemoteObject .java

public class UnicastRemoteObject extends RemoteServer {

    //暴露此服务到哪个端口
    private int port = 0;

    //客户端的Socket工厂(如果有的话)
    private RMIClientSocketFactory csf = null;

    //服务端的Socket工厂(如果有的话)
    private RMIServerSocketFactory ssf = null;
    //jdk1.1 
    private static final long serialVersionUID = 4974527148936298033L;

    //暴露此服务,同时设置通信的端口
    protected UnicastRemoteObject() throws RemoteException
    {
        this(0);//端口为0将使用匿名(anonymous)端口1099
    }
    protected UnicastRemoteObject(int port) throws RemoteException;

    //jdk1.2 起
    protected UnicastRemoteObject(int port,RMIClientSocketFactory csf,RMIServerSocketFactory ssf)throws RemoteException;
    public Object clone() throws CloneNotSupportedException;
    @Deprecated
    public static RemoteStub exportObject(Remote obj)throws RemoteException;
    public static Remote exportObject(Remote obj, int port)throws RemoteException
    public static Remote exportObject(Remote obj, int port,RMIClientSocketFactory csf,RMIServerSocketFactory ssf) throws RemoteException;
    public static boolean unexportObject(Remote obj, boolean force)throws java.rmi.NoSuchObjectException;
}

2、Registry 接口(注册与绑定远程对象的接口)

绑定某个远程对象到某个地址。

Registry 接口定义:

public interface Registry extends Remote{

    //默认注册在1099 端口
    public static final int REGISTRY_PORT = 1099;
    //lookup
    public Remote lookup(String name)throws RemoteException, NotBoundException, AccessException;
    //bind
    public void bind(String name, Remote obj)throws RemoteException, AlreadyBoundException, AccessException;
    //unbind
    public void unbind(String name)throws RemoteException, NotBoundException, AccessException;
    //rebind
    public void rebind(String name, Remote obj)throws RemoteException, AccessException;
    //list
    public String[] list() throws RemoteException, AccessException;
}

3、LocateRegistry (final 工具类):

用于获得上面的Registry 接口对象。即获得远程对象的与某个主机与端口关联的注册对象。

public final class LocateRegistry{

    //此处只展示公有属性与方法

    //返回localhost 的1099 端口的注册对象

    public static Registry getRegistry();

    //返回localhost指定端口的注册对象
    public static Registry getRegistry(int port);

    //返回某个主机的1099 端口的注册对象
    public static Registry getRegistry(String host)throws RemoteException;//端口默认1099

    public static Registry getRegistry(String host, int port)throws RemoteException

    //还指定通信使用的对象
    public static Registry getRegistry(String host, int port, RMIClientSocketFactory csf)throws RemoteException

    //在本地创建一个注册对象并暴露,并指定只接受哪个端口的请求。port:仅来源于该port 的请求能访问该注册对象上注册的
    //远程服务。暴露过程就类似 UnicastRemoteObject.exportObject(Remote,int)被调用一样
    public static Registry createRegistry(int port) throws RemoteException

    public static Registry createRegistry(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf) throws
       RemoteException

}

3、Naming 工具类(final 类工具类)

上面的LocalRegistry 类用户获得注册对象,而该类用于在注册对象上绑定与获得远程对象(Remote 对象)。

public final class Naming{

    //name:URL 格式的名字,返回一个Remote 对象的参考。即在注册机处查找远程服务。
    public static Remote lookup(String name) throws NotBoundException,RemoteException;

    //name:同上。obj:远程对象。
    public static void bind(String name,Remote obj) throws AlreadyBoundException,RemoteException;

    //解绑定
    public static void unbind(String name)throws NotBoundException,RemoteException;

    //重新绑定(重新指为某个名字绑定新的远程对象,该名字对应的所有旧的绑定都将被该绑定替换)
    public static void rebind(String name,Remote obj) throws RemoteException,java.net.MalformedURLException;

    //查找登记处已绑定的所有名字
    public static String[] list(String name) throws RemoteException,java.net.MalformedURLException;
}
说明:

通过源码可知,Naming 类的方法是首先通过传入的name 参数(URL)查找在该URL 主机与端口上注册的注册对象,然后通过调用该注册对象的lookup、unbind 等方法实现将Remote 对象绑定与解绑的。即可通过Naming 发布远程服务,而不需通过Registry 对象。


疑问:UnicastRemoteObject .java 的 exportObject 方法与 Naming 类的bind 方法有什么区别?

前者仅用于将远程对象(服务对象)注册到localhost 的某个端口,而后者除了可以注册到本地某端口,也可注册到某个主机某端口,同时还可进行解绑,重新绑定等操作。


小结:

Remote 接口:提供远程服务的对象;

Registry 接口:绑定远程服务对象的接口;

LocalRegistry 类:创建并暴露与某个主机某个端口绑定的Registry 对象的工具类;

Naming 类:绑定Remote 服务到某个URL(实际还是调用了LocalRegistry 获得Registry ,最终通过Registry 实现绑定的);

UnicastRemoteObject 类:Remote 接口的实现类,所有的远程服务类都必须继承该类或另外一个类(Activatable 类)。该类可以将自己绑定到某个端口,而不需通过Naming 等类。


注:

以URL 形式的参数作为绑定name:http://localhost:1099/remoteObjName


三、RMI 基础实践


四、RMI 与 Spring 实践






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值