初识Java RMI框架

13 篇文章 2 订阅
1 篇文章 0 订阅

一、什么RMI


RMI即(Rmote Method Invoke)远程方法调用。换句话说客户对象Client可以调用远程Server上的方法。客户端并不是直接调用远程服务上的方法,而是通过客户辅助对象与远程服务通信。客户辅助对象会联系服务器,传送相应的调用信息,等待服务器的返回。在服务器端,存在一个服务器辅助对象,该服务器辅助对象从客户端辅助对象中接收请求(通过Socket连接),将请求交由真正的服务对象处理。最后服务器辅助对象将从服务中的得到的处理结果打包,然后发送给客户辅助对象(通过Socket输出流),客户辅助对象将得到的结果解包,最后将返回结果交给客户端。在RMI中将客户端辅助对象称为存根Stub,将服务器辅助对象称为骨架Skeleton

二、RMI通信流程


RMI通信流程图

三、JAVA RMI 的一个简单DEMO


制作一个可供远程调用的对象,需要该类或者接口实现或者继承java.rmi.Remote接口。该接口为一个标记接口,其中不含有任何可供实现的方法。只用实现或集成该接口的类,才能成为一个可供调用的远程对象。
同时应该注意远程方法的参数和返回值应该为java基本类型或者Serializable类型。

为了简单起见一下源码不采用包结构。

MyService接口源码:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MyService extends Remote { // 继承Remote接口
    // 定义能被远程调用的方法
    String service(String content) throws RemoteException;
}

实现该接口,MyServiceImpl源码:


import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

// 需要继承UnicastRemoteObject类,用于导出的远程对象和获得与该远程对象通信的存根
public class MyServiceImpl extends UnicastRemoteObject implements MyService {

    private static final long serialVersionUID = -3145731787217567264L;

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

    // 实现服务方法
    public String service(String content) {
        return "server >> " + content;
    }

}

Server类源码:

import java.rmi.Naming;

public class Server {
    public static void main(String[] args) {
        try {
            // 实例化服务类
            MyService service = new MyServiceImpl();
            // 将该服务注册到RMI Registry中,服务名为service
            // 当绑定服务对象时,RMI会把服务换成Stub,然后把Stub放入registry中
            Naming.rebind("service", service);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("register");
    }
}

Client类源码:

import java.rmi.Naming;

public class Client {
    public static void main(String[] args) {
        // service为服务端注册的服务名
        String url = "rmi://localhost/service";
        try {
            // 客户端到RMI Registry中查找服务
            MyService service = (MyService) Naming.lookup(url);
            Class stubClass = service.getClass();
            System.out.println(stubClass + " 是 " + stubClass.getName() + "的实例");
            Class[] infaces = stubClass.getInterfaces();
            for(Class c : infaces) {
                System.out.println("stub实现了" + c.getName() + "接口");
            }
            // 调用服务的方法并打印返回的结果
            System.out.println(service.service(args[0]));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

注意,为了简单起见所有源码放在一个文件夹下

1.编译源码生成.class文件

// 指定编码为UTF-8
javac -encoding utf-8 *.java

编译源码

2.通过rmic生成stub和skeleton,rmic为JDK内置工具,通过该工具生成后缀为_Stub和_Skel的文件(实际并未产生后缀为_Skel的骨架文件,经过查询发现Jdk1.2后不需要生成该文件)

// 注意是通过实现类生成,而不是接口
rmic MyServiceImpl

生成Stub文件

这里写图片描述

3.开启另一个命令行窗口,执行rmiregistry注意该命令行窗口必须在源码所在目录打开(很重要),不然会报错
注册服务

4.启动服务(启动服务前必须保证rmiregistry运行)

java Server

启动服务

5.运行客户端代码

java Client Hello,world!

这里写图片描述

四、后记

将生成的_Stub后缀文件删除,重新运行Server和Client发现不一样的运行结果。似乎生成了代理类(不是很清楚,待了解!)
这里写图片描述

参考:

http://haolloyin.blog.51cto.com/1177454/332426/
https://segmentfault.com/a/1190000002737588
《Head First设计模式》

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值