RMI技术和远程代理

远程代理概念


定义

远程代理就是”远程对象的本地代表”。”远程对象”就是一个活在不同JAVA虚拟机(JVM)堆里,即在不同的地址空间中代表同一对象。“”本地代表“就是可以像在本地方法一样调用的对象,其行为转发到远程对象。远程代理就是为了让远程调用看起来跟本地调用对象一样,毫无瑕疵。

结构

这里写图片描述

这里有四个角色。客户对象,客户代理对象(客户辅助对象),服务辅助对象,服务对象
1.客户对象,就是本队客户端用户,他以为是在跟真正的服务沟通,以为客户代理对象就是真正做事情的对象
2.客户代理对象假装自己就是一个真正的服务,但实际上它只是真东西的一个代理
3.服务辅助对象从客户代理对象取得请求,对它解包,调用真正服务上的方法
4.服务对象才是真正提供服务的地方,他真正在做事

JAVA RMI概述

RMI介绍

JAVA RMI技术就是典型的远程代理案例。
RMI提供了客户辅助对象和服务辅助对象,也为客户辅助对象创建了和服务对象相同的方法。RMI的好处是可以不必写任何网络或I/O代码,就可以让客户程序跟在本地JVM正常调用方法一样调用远程方法(真正的服务所在的方法)。但是虽然调用远程方法跟本地一样,但是客户辅助对象还是需要通过网络发送方法调用的,所以网络和I/O还是存在的。

RMI术语

RMI将客户辅助对象成为stub(桩),把服务辅助对象称为skeleton(骨架)

JAVA RMI实例

制作远程服务

  1. 制作远程接口

     定义供客户远程调用的服务方法接口。客户对象会把它作为服务的超类,Stub(客户辅助对象)和服务对象都会实现该接口
    
  2. 制作远程的实现类

     服务对象,实现远程接口定义的远程方法,也是客户真正想调用的对象,也是真正工作的对象
    
  3. 利用rmic产生的stub和skeleton

    rmic是一个工具,用于生成客户辅助对象和服务辅助对象,可以在JDK中找到rmic
    
  4. 启用RMI registry

    rmi registry是电话普,客户可以在其中找到客户代理对象(客户辅助对象)的位置,也就是客户的一个Stub helper对象
    
  5. 开始远程服务

    让服务对象运行起来,服务实现类回去实例化一个服务实例,然后将这个服务注册到 RMI reigistry,注册后客户就可以调用了
    

制作远程服务具体实施

  • 制作远程接口

    1.接口扩展java.rmi.Remote
        Remote类是一个记号接口,不包含任何方法,但是是RMI的规范,所以要遵守规则
    2.声明的所有方法都抛出RemoteException
        客户会调用实现远程接口的stub上的方法,stub底层用到了网络和I/O,可能产生异常
    3.要确定变量和返回值都是源于类型或者可序列化类型
        远程方法的变量必须被打包并通过网络运输,需要序列化完成。如果是源于类型,字符串和许多API定义的类型(包括数组和集合),都没问题,如果是自定义类,那么要实现Serializable。
    

最终代码效果

public interface MyRemote extends Remote{

    public String getName() throws RemoteException;
}
  • 制作远程实现

    1.服务实现类必须实现服务接口
    2.服务实现类必须扩展UnicastRemoteObject对象
        要成为远程服务对象,对象需要一些远程的功能,由超类为你完成
    3.设计无参构造器,抛出RemoteException
        这是由于超类UnicastRemoteObject的构造器会抛出异常。那么当服务实现类被实例化,超类构造器会被调用。如果超类构造器抛异常,那么子类也就能抛异常了
    4.用RMI Registry注册服务
        为了保证被客户对象调用,那么需要服务实例化,然后放进RMI registry。看似绑定服务对象,
        但实际上RMI注册的是stub,毕竟registry是关于客户辅助对象的电话本
        注册服务使用java.rmi.Naming类的静态方法rebind()
    

最终代码效果

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{

    protected MyRemoteImpl() throws RemoteException {
        super();
    }

    @Override
    public String getName() throws RemoteException {
        return "哈哈哈";
    }

}

进行第四步,注册服务是需要保证RMI registry已经启动,你才能注册

注册代码

    try {
            MyRemote service = new MyRemoteImpl();
            Registry registry = LocateRegistry.createRegistry(2500);
            registry.bind("myRemote", service);
        } catch (Exception e) {
            e.printStackTrace();
        }

关于rmi的端口默认是1099,这里换成2500

关于如何在eclipse使用RMI registry和RMIC工具,详情见
https://blog.csdn.net/bigtree_3721/article/details/50615702

  • 使用rmic工具产生stub和skeleton

    eclipse可以图形化界面生产,具体可以看上面的帖子

  • 启动Rim registry

    可以在项目类路径下使用dos命令:rmiregistry启动,但是启动的1099。也可以上图帖子启动

  • 启动服务

    可以在创建一个类,作为服务启动类,main方法中放置上面关于注册服务的代码,即可启动

客户端如何使用?

客户端首先需要MyRemote这个接口类,毕竟这是关于服务的类。具体代码如下:

        MyRemote myremote = (MyRemote) Naming.lookup("rmi://127.0.0.1:2500/myRemote");
        String name = myremote.getName();
        System.out.println(name);
Naming.lookup方法返回的是Object,需要强转。
127.0.0.12500是指服务的所在ip和端口号。
myRemote是服务类在RMI Registry的注册名,便于客户端找到

客户端运行流程
这里写图片描述

1.客户到RMI registry中寻找
2.RMI registry返回Stub对象
3.客户调用Stub的方法,就好像Stub是真正的服务对象一样

RMI需要注意的三个点:

1.启动远程服务绑定设备前,要先启动rmiregistry。如果使用Naming.rebind()注册服务的话。如果使用LocateRegistry创建registry的话,那么不需要
2.记得把变量和返回值类型定为可序列化。
3.记得给客户提供stub类,在服务端的时候要用rmic工具创建

猜你喜欢

转载自blog.csdn.net/qq_32020035/article/details/81039106