(转)Java RMI远程方法调用详解
Java RMI远程方法调用详解
而RPC是远程过程调用(Remote Procedure Call)可以用于一个进程调用另一个进程(很可能在另一个远程主机上)中的过程,从而提供了过程的分布能力。Java 的 RMI 则在 RPC 的基础上向前又迈进了一步,即提供分布式对象间的通讯。
二、Java RMI 简单示例
(2)创建远程类:实现远程接口。
(3)创建服务器程序:创建远程对象,通过createRegistry()方法注册远程对象。并通过bind或者rebind方法,把远程对象绑定到指定名称空间(URL)中。
(4)创建客户程序:通过 lookup()方法查找远程对象,进行远程方法调用
(1)创建远程接口:继承java.rmi.Remote接口。
(a)直接或间接继承java.rmi.Remote接口。
(2)创建远程类:实现远程接口。
(a)导出为远程对象的第一种方式:使远程类实现远程接口时,同时继承java.rmi.server.UnicastRemoteObject类,并且远程类的构造方法必须声明抛出RemoteException。这是最常用的方式,下面的本例子就采取这种方式。
- public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface
public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface
- public class RemoteImpl extends OtherClass implements RemoteInterface{
- private String name;
- public RemoteImpl (String name)throws RemoteException{
- this.name=name;
- UnicastRemoteObject.exportObject(this,0);
- }
public class RemoteImpl extends OtherClass implements RemoteInterface{private String name;public RemoteImpl (String name)throws RemoteException{this.name=name;UnicastRemoteObject.exportObject(this,0);}
在构造方法RemoteImpl 中调用了UnicastRemoteObject.exportObject(this,0)方法,将自身导出为远程对象。
- protected UnicastRemoteObject(int port) throws RemoteException
- {
- this.port = port;
- exportObject((Remote) this, port);
- }
protected UnicastRemoteObject(int port) throws RemoteException{this.port = port;exportObject((Remote) this, port);}
- public static Remote exportObject(Remote obj, int port)
- throws RemoteException
- {
- return exportObject(obj, new UnicastServerRef(port));
- }
public static Remote exportObject(Remote obj, int port)throws RemoteException{return exportObject(obj, new UnicastServerRef(port));}
exportObject(Remote obj, int port),该方法负责把参数obj指定的对象导出为远程对象,使它具有相应的存根(Stub),并监听远程客户的方法调用请求;参数port指导监听的端口,如果值为0,表示监听任意一个匿名端口。
(3)创建服务器程序:创建远程对象,在rmiregistry注册表中注册远程对象,并绑定到指定的URL中。
【1】 bind(String name,Object obj):注册对象,把对象与一个名字name绑定,这里的name其实就是URL格式。如果该名字已经与其它对象绑定,就会抛出NameAlreadyBoundException。
【2】rebind(String name,Object obj):注册对象,把对象与一个名字绑定。如果该名字已经与其它对象绑定,不会抛出NameAlreadyBoundException,而是把当前参数obj指定的对象覆盖原先的对象。
【3】 lookup(String name):查找对象,返回与参数name指定的名字所绑定的对象。
【4】unbind(String name):注销对象,取消对象与名字的绑定。
- RemoteInterface remoteObj2 = new RemoteImpl();// 创建远程对象
- Context namingContext = new InitialContext();// 初始化命名内容
- LocateRegistry.createRegistry(8892);// 在本地主机上创建和导出注册表实例,并在指定的端口上接受请求
- namingContext.rebind(”rmi://localhost:8892/RemoteObj2”, remoteObj2);// 注册对象,即把对象与一个名字绑定。
RemoteInterface remoteObj2 = new RemoteImpl();// 创建远程对象
Context namingContext = new InitialContext();// 初始化命名内容
LocateRegistry.createRegistry(8892);// 在本地主机上创建和导出注册表实例,并在指定的端口上接受请求
namingContext.rebind("rmi://localhost:8892/RemoteObj2", remoteObj2);// 注册对象,即把对象与一个名字绑定。
- RemoteInterface remoteObj = new RemoteImpl();
- LocateRegistry.createRegistry(8891);
- Naming.rebind(”rmi://localhost:8891/RemoteObj”, remoteObj);
RemoteInterface remoteObj = new RemoteImpl();
LocateRegistry.createRegistry(8891);
Naming.rebind("rmi://localhost:8891/RemoteObj", remoteObj);
(4)创建客户程序:通过 lookup()方法查找远程对象,进行远程方法调用
- Context namingContext = new InitialContext();// 初始化命名内容
- RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup(”rmi://localhost:8892/RemoteObj2”);//获得远程对象的存根对象
- System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法
Context namingContext = new InitialContext();// 初始化命名内容
RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//获得远程对象的存根对象
System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法
在JDK1.3版本或更低的版本,如下方式调用;
- RemoteInterface RmObj = (RemoteInterface) Naming.lookup(“rmi://localhost:8891/RemoteObj”);
- System.out.println(RmObj.doSomething());
RemoteInterface RmObj = (RemoteInterface) Naming.lookup("rmi://localhost:8891/RemoteObj");
System.out.println(RmObj.doSomething());
- package rmi;
- import java.rmi.Remote;
- import java.rmi.RemoteException;
- //声明一个远程接口RemoteInterface,该接口必须继承Remote接口
- //接口中需要被远程调用的方法,必须抛出RemoteException异常
- public interface RemoteInterface extends Remote {
- // 声明一个doSomething方法
- public String doSomething() throws RemoteException;
- // 声明一个计算方法Calculate
- public int Calculate(int num1, int num2) throws RemoteException;
- }
package rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
//声明一个远程接口RemoteInterface,该接口必须继承Remote接口
//接口中需要被远程调用的方法,必须抛出RemoteException异常
public interface RemoteInterface extends Remote {// 声明一个doSomething方法public String doSomething() throws RemoteException;// 声明一个计算方法Calculatepublic int Calculate(int num1, int num2) throws RemoteException;
}
2. 创建远程类:实现远程接口
- package rmi;
- import java.rmi.RemoteException;
- import java.rmi.server.UnicastRemoteObject;
- //实现远程接口RemoteInterface,并继承UnicastRemoteObject
- //注意RemoteObject这个类,实现了Serializable, Remote这两个接口
- public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface {
- // 这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常
- public RemoteImpl() throws RemoteException {
- }
- // 实现doSomething方法
- public String doSomething() throws RemoteException {
- return “OK ,You can do……”;
- }
- // 实现Calculate方法,返回计算结果
- public int Calculate(int num1, int num2) throws RemoteException {
- return (num1 + num2);
- }
- }
package rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
//实现远程接口RemoteInterface,并继承UnicastRemoteObject
//注意RemoteObject这个类,实现了Serializable, Remote这两个接口
public class RemoteImpl extends UnicastRemoteObject implements RemoteInterface {// 这个实现必须有一个显式的构造函数,并且要抛出一个RemoteException异常public RemoteImpl() throws RemoteException {}// 实现doSomething方法public String doSomething() throws RemoteException {return "OK ,You can do......";}// 实现Calculate方法,返回计算结果public int Calculate(int num1, int num2) throws RemoteException {return (num1 + num2);}
}
- package rmi2;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import rmi.RemoteInterface;
- public class ClientTest {
- public static void main(String args[]) {
- try {
- Context namingContext = new InitialContext();// 初始化命名内容
- RemoteInterface RmObj2 = (RemoteInterface) namingContext
- .lookup(”rmi://localhost:8892/RemoteObj2”);//获得远程对象的存根对象
- System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法
- System.out.println(”远程服务器计算结果为:” + RmObj2.Calculate(90, 2));
- } catch (Exception e) {
- }
- }
- }
package rmi2;
import javax.naming.Context;
import javax.naming.InitialContext;import rmi.RemoteInterface;public class ClientTest {public static void main(String args[]) {try {Context namingContext = new InitialContext();// 初始化命名内容RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//获得远程对象的存根对象System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法System.out.println("远程服务器计算结果为:" + RmObj2.Calculate(90, 2));} catch (Exception e) {}}
}
在JDK1.3版本或更低的版本,如下方式注册;
- package rmi;
- import java.net.MalformedURLException;
- import java.rmi.AlreadyBoundException;
- import java.rmi.Naming;
- import java.rmi.RemoteException;
- import java.rmi.registry.LocateRegistry;
- //在JDK1.3版本或更低的版本,需要使用java.rmi.Naming来注册远程对象
- //创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
- public class RMIServer {
- public static void main(String args[])
- throws java.rmi.AlreadyBoundException {
- try {
- // 创建一个远程对象RemoteObj,实质上隐含了是生成stub和skeleton,并返回stub代理引用
- RemoteInterface remoteObj = new RemoteImpl();
- // 本地创建并启动RMI Service,被创建的Registry服务将在指定的端口,侦听请求
- // Java默认端口是1099,缺少注册表创建,则无法绑定对象到远程注册表上
- LocateRegistry.createRegistry(8891);
- // 把远程对象注册到RMI注册服务器上,并命名为RemoteObj(名字可自定义,客户端要对应)
- // 绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
- Naming.rebind(”rmi://localhost:8891/RemoteObj”, remoteObj);// 将stub代理绑定到Registry服务的URL上
- // Naming.bind(“//localhost:8880/RemoteObj”,remoteObj);
- System.out.println(”>>>>>INFO:远程IHello对象绑定成功!”);
- } catch (RemoteException e) {
- System.out.println(”创建远程对象发生异常!”);
- e.printStackTrace();
- } catch (MalformedURLException e) {
- System.out.println(”发生URL畸形异常!”);
- e.printStackTrace();
- }
- }
- }
package rmi;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
//在JDK1.3版本或更低的版本,需要使用java.rmi.Naming来注册远程对象
//创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
public class RMIServer {public static void main(String args[])throws java.rmi.AlreadyBoundException {try {// 创建一个远程对象RemoteObj,实质上隐含了是生成stub和skeleton,并返回stub代理引用RemoteInterface remoteObj = new RemoteImpl();// 本地创建并启动RMI Service,被创建的Registry服务将在指定的端口,侦听请求// Java默认端口是1099,缺少注册表创建,则无法绑定对象到远程注册表上LocateRegistry.createRegistry(8891);// 把远程对象注册到RMI注册服务器上,并命名为RemoteObj(名字可自定义,客户端要对应)// 绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)Naming.rebind("rmi://localhost:8891/RemoteObj", remoteObj);// 将stub代理绑定到Registry服务的URL上// Naming.bind("//localhost:8880/RemoteObj",remoteObj);System.out.println(">>>>>INFO:远程IHello对象绑定成功!");} catch (RemoteException e) {System.out.println("创建远程对象发生异常!");e.printStackTrace();} catch (MalformedURLException e) {System.out.println("发生URL畸形异常!");e.printStackTrace();}}
}
4. 客户端代码
- package rmi2;
- import javax.naming.Context;
- import javax.naming.InitialContext;
- import rmi.RemoteInterface;
- public class ClientTest {
- public static void main(String args[]) {
- try {
- Context namingContext = new InitialContext();// 初始化命名内容
- RemoteInterface RmObj2 = (RemoteInterface) namingContext
- .lookup(”rmi://localhost:8892/RemoteObj2”);//获得远程对象的存根对象
- System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法
- System.out.println(”远程服务器计算结果为:” + RmObj2.Calculate(90, 2));
- } catch (Exception e) {
- }
- }
- }
package rmi2;
import javax.naming.Context;
import javax.naming.InitialContext;import rmi.RemoteInterface;
public class ClientTest {public static void main(String args[]) {try {Context namingContext = new InitialContext();// 初始化命名内容RemoteInterface RmObj2 = (RemoteInterface) namingContext.lookup("rmi://localhost:8892/RemoteObj2");//获得远程对象的存根对象System.out.println(RmObj2.doSomething());//通过远程对象,调用doSomething方法System.out.println("远程服务器计算结果为:" + RmObj2.Calculate(90, 2));} catch (Exception e) {}}
}
在JDK1.3版本或更低的版本,如下方式调用
- import java.net.MalformedURLException;
- import java.rmi.Naming;
- import java.rmi.NotBoundException;
- import java.rmi.RemoteException;
- public class ClientTest {
- public static void main(String args[]) {
- try {
- // 在RMI服务注册表中查找名称为RemoteObj的对象,并调用其上的方法
- // 客户端通过命名服务Naming获得指向远程对象的远程引用
- RemoteInterface RmObj = (RemoteInterface) Naming
- .lookup(”rmi://localhost:8881/RemoteObj”);
- System.out.println(RmObj.doSomething());
- System.out.println(”远程服务器计算结果为:” + RmObj.Calculate(1, 2));
- } catch (NotBoundException e) {
- e.printStackTrace();
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;public class ClientTest {public static void main(String args[]) {try {// 在RMI服务注册表中查找名称为RemoteObj的对象,并调用其上的方法// 客户端通过命名服务Naming获得指向远程对象的远程引用RemoteInterface RmObj = (RemoteInterface) Naming.lookup("rmi://localhost:8881/RemoteObj");System.out.println(RmObj.doSomething());System.out.println("远程服务器计算结果为:" + RmObj.Calculate(1, 2));} catch (NotBoundException e) {e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}}
}
- OK ,You can do……
- 远程服务器计算结果为:92
OK ,You can do......
远程服务器计算结果为:92
例子代码下载:http://download.csdn.net/detail/guyuealian/9583633
(转)Java RMI远程方法调用详解相关推荐
- Java RMI远程方法调用详解
Java RMI远程方法调用详解 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51992182 一.Java R ...
- Java RMI、JRMP详解
JRMP Java远程方法协议(Java Remote Method Protocol,JRMP),适用于RMI过程中的协议,只有使用这个协议,方法调用双方才能正常进行数据交流. RMI 远程方法调用 ...
- Java单元测试之JUnit4详解
2019独角兽企业重金招聘Python工程师标准>>> Java单元测试之JUnit4详解 与JUnit3不同,JUnit4通过注解的方式来识别测试方法.目前支持的主要注解有: @B ...
- java -jar 和 -cp详解
java -jar 和 -cp详解 命令行执行程序 假如我们有一个程序,把它打包成Test.jar,如何运行才能成功输出Hello World package com.test; public cla ...
- java访问修饰符详解——学java,零基础不怕,不只要理论,更要实践+项目,a href=http://www.bjweixin.com太原维信科技提供 /a...
java访问修饰符详解--学java,零基础不怕,不只要理论,更要实践+项目 <a href=http://www.bjweixin.com>太原维信科技提供 </a> pub ...
- Java编程配置思路详解
Java编程配置思路详解 SpringBoot虽然提供了很多优秀的starter帮助我们快速开发,可实际生产环境的特殊性,我们依然需要对默认整合配置做自定义操作,提高程序的可控性,虽然你配的不一定比官 ...
- Java 8 Stream API详解--转
原文地址:http://blog.csdn.net/chszs/article/details/47038607 Java 8 Stream API详解 一.Stream API介绍 Java 8引入 ...
- 你真的弄明白了吗?Java并发之AQS详解
你真的弄明白了吗?Java并发之AQS详解 带着问题阅读 1.什么是AQS,它有什么作用,核心思想是什么 2.AQS中的独占锁和共享锁原理是什么,AQS提供的锁机制是公平锁还是非公平锁 3.AQS在J ...
- java定时任务框架elasticjob详解
这篇文章主要介绍了java定时任务框架elasticjob详解,Elastic-Job是ddframe中dd-job的作业模块中分离出来的分布式弹性作业框架.该项目基于成熟的开源产品Quartz和Zo ...
最新文章
- 知识蒸馏在推荐系统的应用
- Python文件与目录操作
- telnet不能用,提示:-bash: telnet: command not found
- sunos 查cpu主频指令prtdiag
- 类string的构造函数、拷贝构造函数和析构函数
- 数据库中字段随机添加汉字
- 幻想乡三连A:五颜六色的幻想乡
- 企业管理器开启和关闭数据库时出现Error Messsage
- cct2级考试c语言试题,CCT2样题
- php dp0,DOS批处理中%cd%与%~dp0的区别详解
- NVIDIA cuDNN 下载
- 求助动态贝叶斯网络参数学习函数的使用方法
- 卡方分布、t分布、F分布
- 汇总我关注的技术博主的2021年度总结
- qchart 怎么点击一下 出一条线_动漫日系雨伞怎么画?教你用集中线尺画一把日本雨伞!...
- 使用cairo和freetype进行字体布局和渲染
- 背后的力量 | 升级电子病历基础架构 华云数据助力华中科技大学同济医学院附属协和医院打造就医新模式
- python脚本自动消除安卓版_微信跳一跳脚本重出江湖,python实现安卓iOS自动版与手动版!...
- 基于arduino超声波测距学习
- 辨别 利用AAC转成无损格式音乐 的假无损