Java RMI使用

什么是RMI

RMI,全称Remote Method Invoke,远程方法调用。它能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。它的强大之处就体现在开发分布式网络应用的能力上,是纯Java的网络分布式应用系统的核心解决方案之一。它支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。

RMI目前使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信。由于JRMP是专为Java对象制定的,Java RMI具有Java的"Write Once,Run Anywhere"的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。

RMI可利用标准Java本机方法接口JNI与现有的和原有的系统相连接。RMI还可利用标准JDBC包与现有的关系数据库连接。RMI/JNI和RMI/JDBC相结合,可帮助您利用RMI与目前使用非Java语言的现有服务器进行通信,而且在您需要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。

RMI的基础是接口,RMI构建基于一个重要的原理:定义接口和定义接口的具体实现是分开的。下面通过一个例子,演示如何使用Java RMI。

使用Java RMI

话不多说了,先看下项目结构图:

注意这里是两个项目,可以将Server与Client放在不同的机器上执行,我只有一台机器,所以只能将它们分成两个不同的项目了。

然后上代码(我也是一边学习一边测试,然后记录整个过程,因此这个接口就是大家见过的啦)

服务器端

1. 接口定义(RmiService.java):

1package com.abc.rmi.service; 2 3import java.rmi.Remote; 4 5public interface RmiService extends Remote { 6    public double add(double a,double b) throws java.rmi.RemoteException;  7    public double sub(double a,double b) throws java.rmi.RemoteException;  8    public double mul(double a,double b) throws java.rmi.RemoteException;  9    public double div(double a,double b) throws java.rmi.RemoteException; 10    public double max(double a,double b) throws java.rmi.RemoteException; 11    public double min(double a,double b) throws java.rmi.RemoteException; 12    public double avg(double a,double b) throws java.rmi.RemoteException; 13}

这个接口需要继承自Rmi的Remote接口。官方文档中这样说:

Any object that is a remote object must directly or indirectly implement this interface. Only those methods specified in a "remote interface", an interface that extends java.rmi.Remote are available remotely. 

注意,每一个方法声明都必须抛出java.rmi.RemoteException,否则在启动Server的时候会报以下错误

1Rmi Server start failed: java.rmi.server.ExportException: remote object implements illegal remote interface; nested exception is:  2 java.lang.IllegalArgumentException: illegal remote method encountered: public abstract double com.abc.rmi.service.RmiService.add(double,double)

2.  接口实现(RmiServiceImpl.java):

1package com.abc.rmi.service.impl; 2 3import java.rmi.RemoteException; 4import java.rmi.server.UnicastRemoteObject; 5import com.abc.rmi.service.RmiService; 6 7public class RmiServiceImpl extends UnicastRemoteObject implements RmiService { 8    private static final long serialVersionUID = -317455609230764324L; 9    public RmiServiceImpl() throws RemoteException { 10        super(); 11    } 12 13    @Override 14    public double add(double a, double b) throws RemoteException { 15        return a + b; 16    } 17    @Override 18    public double sub(double a, double b) throws RemoteException { 19        return a - b; 20    } 21    @Override 22    public double mul(double a, double b) throws RemoteException { 23        return a * b; 24    } 25    @Override 26    public double div(double a, double b) throws RemoteException { 27        return a / b; 28    } 29    @Override 30    public double max(double a, double b) throws RemoteException { 31        return a > b ? a : b; 32    } 33    @Override 34    public double min(double a, double b) throws RemoteException { 35        return a < b ? a : b; 36    } 37    @Override 38    public double avg(double a, double b) throws RemoteException { 39        return (+ b) / 2; 40    } 41}

这个实现类使用了UnicastRemoteObject去联接RMI系统。这里我们继承了UnicastRemoteObject这个类它的作用是

事实上并不一定要这样做,如果一个类不是从UnicastRmeoteObject上继承,那必须使用它的exportObject()方法去联接到RMI。

如果**一个类继承自UnicastRemoteObject,**那么它必须提供一个构造函数并且声明抛出一个RemoteException对象。当这个构造函数调用了super(),它将激活UnicastRemoteObject中的代码完成RMI的连接和远程对象的初始化。

3. 把方法注册到机器上(RmiServer.java):

1package com.abc.rmi; 2 3import java.rmi.Naming; 4import java.rmi.registry.LocateRegistry; 5 6import com.abc.rmi.service.impl.RmiServiceImpl; 7 8/** 9 * 启动 RMI 注册服务并进行对象注册 10 */ 11public class RmiServer { 12    private static final String RMI_HOST = "192.168.15.44"; 13    private static final int RMI_PORT = 6666; 14    private static final String RMI_URL = "rmi://" + RMI_HOST + ":" + RMI_PORT + "/RmiServer"; 15     16    public static void main(String[] argv) { 17        try { 18            LocateRegistry.createRegistry(RMI_PORT); 19            Naming.bind(RMI_URL, new RmiServiceImpl()); 20            System.out.println("Rmi Server[" + RMI_HOST + ":" + RMI_PORT + "] start success." ); 21        } catch (Exception e) { 22            System.out.println("Rmi Server start failed: " + e); 23        } 24    } 25}

到此为止,Server端的代码结束。

客户端

  1. 将服务器端的RmiService拷贝到项目结构图的位置。

2. 客户端调用(RmiClient.java):

1package com.abc.rmi; 2 3import java.rmi.Naming; 4import com.abc.rmi.service.RmiService; 5 6public class RmiClient { 7    public static void main(String args[]) throws Exception { 8        RmiService rmi = (RmiService) Naming.lookup("rmi://192.168.15.44:6666/RmiServer"); 9        System.out.println(rmi.add(100, 10)); 10        System.out.println(rmi.sub(100, 10)); 11        System.out.println(rmi.mul(100, 10)); 12        System.out.println(rmi.div(100, 10)); 13        System.out.println(rmi.max(100, 10)); 14        System.out.println(rmi.min(100, 10)); 15        System.out.println(rmi.avg(100, 10)); 16    } 17}

注意这里的URL需要和Server端定义的一样。

运行测试

先运行RmiServer,

再运行RmiClient,看执行结果:

中间可能会遇到类似这样的错误:

1Exception in thread “main” java.security.AccessControlException: access denied (  2java.net.SocketPermission 192.168.15.44:6666 connect,resolve)

此时需要配置java.policy。打开%JAVA_HOME%/jre/lib/security/java.policy,添加这么一行:

permission java.net.SocketPermission "192.168.15.44:6666","listen,accept,connect,resolve";

保存后重启Server和Client即可。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java 复制Map对象(深拷贝与浅拷贝)

java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象

Java日期时间API系列31

  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )