Java RMI详解
来源:互联网 发布:excel多张表格数据汇总 编辑:程序博客网 时间:2024/05/05 06:31
Java RMI详解
RMI(Remote Method Invocation,远程方法调用)是用Java在JDK1.2中实现的,它大大增强了Java开发分布式应用的能力。
Java作为一种风靡一时的网络开发语言,其巨大的威力就体现在它强大的开发分布式网络应用的能力上,而RMI就是开发百分之百纯Java的网络分布式应用系统的核心解决方案之一。其实它可以被看作是#RPC#的Java版本。但是传统RPC并不能很好地应用于分布式对象系统。而Java RMI 则支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。
工作方式
运行平台
RMI目前(Java Remote Messaging Protocol)进行通信。JRMP是专为Java的远程对象制定的协议。因此,Java RMI具有Java的”Write Once,Run Anywhere”的优点,是分布式应用系统的百分之百纯Java解决方案。用Java RMI开发的应用系统可以部署在任何支持JRE(Java Run Environment Java,运行环境)的平台上。但由于JRMP是专为Java对象制定的,因此,RMI对于用非Java语言开发的应用系统的支持不足。不能与用非Java语言书写的对象进行通信。
下面将介绍RMI的优点以及如何将其连接到现有的和原有的系统中,以及与。
计算途径
Java Remote Method Invocation (RMI – Java远程方法调用)提供了简单而直接的途径。这些对象可以是新的Java对象,也可以是围绕现有API的简单的Java包装程序。Java体现了“编写一次就能在任何地方运行的模式。而RMI可将Java模式进行扩展,使之可在任何地方运行”。
因为RMI是以Java为核心的,所以,它将Java的安全性和可移植性等强大功能带给了分布式计算。您可将代理和业务逻辑等属性移动到网络中最合适的地方。如果您要扩展Java在系统中的使用,RMI将使您充分利用其强大功能。
RMI还可利用标准JDBC包与现有的关系数据库连接。RMI/JNI和RMI/JDBC相结合,可帮助您利用RMI与目前使用非Java语言的现有服务器进行通信,而且在您需要时可扩展Java在这些服务器上的使用。RMI可帮助您在扩展使用时充分利用Java的强大功能。
RMI客户机类
RMI客户使用java.rmi.Naming.lookup()方法,在指定的远程主机上查找RMI服务对象,若找到就把它转换成本地接口RMIOperate类型。
它与CORBA不同之处在于RMI客户机必须知道提供RMI服务主机的URL,这个URL可以通过rmi://host/path或rmi://host:port/path来指定,如果省略端口号,就默认使用1099。
Java.rmi.Naming.lookup()方法可能产生三个异常:Java.rmi.RemoteException、Java.rmi.NotBoundException、 MalformedURLException,异常都需要捕获。
//HelloClient.javaimport java.rmi.*;public class HelloClient { public static void main(String[] args) { // 在服务器端设置安全机制 /* if (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } */ /* 默认为本地主机和默认端口 */ String host = "localhost:1099"; /* 带输入参数时,将host设置为指定主机 */ if (args.length > 0) host = args[0]; try { /* 根据指定的URL定位远程实现对象 */ /* “h”是一个标识符,我们将用它指向实现“Hello”接口的远程对象 */ Hello h = (Hello) Naming.lookup("rmi://" + host + "/HelloService"); System.out.println("实现“Hello”接口的远程对象: " + h); System.out.println("我在客户端,开始调用RMI服务器端的'sayHello'方法"); System.out.println("欢迎, " + h.sayHello("javamxj blog")); } catch (Exception ex) { System.out.println("错误 " + ex); }}
RMI远程调用步骤:
1,客户对象调用客户端辅助对象上的方法
2,客户端辅助对象打包调用信息(变量,方法名),通过网络发送给服务端辅助对象
3,服务端辅助对象将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象
4,调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象
5,服务端辅助对象将结果打包,发送给客户端辅助对象
6,客户端辅助对象将返回值解包,返回给客户对象
7,客户对象获得返回值
对于客户对象来说,步骤2-6是完全透明的
搭建一个RMI服务的过程分为以下7步
- 创建远程方法接口,该接口必须继承自Remote接口
Remote 接口是一个标识接口,用于标识所包含的方法可以从非本地虚拟机上调用的接口,Remote接口本身不包含任何方法。
package server;import java.rmi.Remote;import java.rmi.RemoteException;public interface Hello extends Remote { public String sayHello(String name) throws RemoteException;}
由于远程方法调用的本质依然是网络通信,只不过隐藏了底层实现,网络通信是经常会出现异常的,所以接口的所有方法都必须抛出RemoteException以说明该方法是有风险的。
- 创建远程方法接口实现类:
UnicastRemoteObject类的构造函数抛出了RemoteException,故其继承类不能使用默认构造函数,继承类的构造函数必须也抛出RemoteException
由于方法参数与返回值最终都将在网络上传输,故必须是可序列化的
package server;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class HelloImpl extends UnicastRemoteObject implements Hello { private static final long serialVersionUID = -271947229644133464L; public HelloImpl() throws RemoteException{ super(); } public String sayHello(String name) throws RemoteException { return "Hello,"+name; }}
利用java自带rmic工具生成sutb存根类(jdk/bin/rmic)
jdk1.2以后的RMI可以通过反射API可以直接将请求发送给真实类,所以不需要skeleton类了
sutb存根为远程方法类在本地的代理,是在服务端代码的基础上生成的,需要HelloImpl.class文件,由于HelloImpl继承了Hello接口,故Hello.class文件也是不可少的。 目录结构:
Test
- - server
- - - - Hello.class
- - - - HelloImpl.class
方式1:
[Test]$ cd /home/name/Test/[Test]$ rmic server.HelloImpl
方式2:
[Test]$ rmic -classpath /home/name/Test server.HelloImpl
运行成功后将会生成HelloImpl_Stub.class文件
启动RMI注册服务(jdk/bin/rmiregistry)
方式一:后台启动rmiregistry服务
[jdk]$jdk/bin/rmiregistry 12312 &[1] 22720[jdk]$ ps -ef|grep rmiregistryname 22720 13763 0 16:43 pts/3 00:00:00jdk/bin/rmiregistry 12312name 22737 13763 0 16:43 pts/3 00:00:00 grep rmiregistry
如果不带具体端口号,则默认为1099
方式二:人工创建rmiregistry服务,需要在代码中添加:
LocateRegistry.createRegistry(12312);
- 编写服务端代码
package server;import java.rmi.Naming;import java.rmi.registry.LocateRegistry;public class HelloServer { public static void main(String[] args) { try{ Hello h = new HelloImpl(); //创建并导出接受指定port请求的本地主机上的Registry实例。 //LocateRegistry.createRegistry(12312); /** Naming 类提供在对象注册表中存储和获得远程对远程对象引用的方法 * Naming 类的每个方法都可将某个名称作为其一个参数, * 该名称是使用以下形式的 URL 格式(没有 scheme 组件)的 java.lang.String: * //host:port/name * host:注册表所在的主机(远程或本地),省略则默认为本地主机 * port:是注册表接受调用的端口号,省略则默认为1099,RMI注册表registry使用的著名端口 * name:是未经注册表解释的简单字符串 */ //Naming.bind("//host:port/name", h); Naming.bind("rmi://192.168.58.164:12312/Hello", h); System.out.println("HelloServer启动成功"); }catch(Exception e){ e.printStackTrace(); } }}
先创建注册表,然后才能在注册表中存储远程对象信息
- 运行服务端:
类class的目录结构
Test- server
- Hello.class
- HelloImpl.class
- HelloServer.class
[path ]$ java server.HelloServer
HelloServer启动成功
- HelloServer.class
当然classpath的设置,否则会报找不到相应的.class文件
- 编写客户端代码
package client;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.NotBoundException;import java.rmi.RemoteException;import server.Hello;public class HelloClient { public static void main(String[] args) { try { Hello h = (Hello)Naming.lookup("rmi://192.168.58.164:12312/Hello"); System.out.println(h.sayHello("zx")); } catch (MalformedURLException e) { System.out.println("url格式异常"); } catch (RemoteException e) { System.out.println("创建对象异常"); e.printStackTrace(); } catch (NotBoundException e) { System.out.println("对象未绑定"); } }}
- 运行客户端
目录结构
Test- client
- HelloClient.class
- server
- Hello.class
- HelloImpl_Stub.class//服务端生成的存根文件
[client]$ java client.HelloClient
Hello,zx
同服务器端,/home/name/Test一定要在CLASSPATH中.
PS:
1. 客户端所在服务和服务端所在的服务器网络一定要通.
java RMI的缺点:
1. 从代码中也可以看到,代码依赖于ip与端口
2. RMI依赖于Java远程消息交换协议JRMP(Java Remote Messaging Protocol),该协议为java定制,要求服务端与客户端都为java编写。
- Java RMI详解
- Java RMI详解
- java RMI原理详解
- Java RMI详解
- Java RMI详解
- Java RMI详解(入门)
- java RMI原理详解
- Java RMI详解
- Java RMI详解
- java rmi 详解
- java RMI原理详解
- Java RMI详解
- java RMI原理详解
- java RMI原理详解
- Java RMI详解
- Java RMI详解
- java RMI远程方法调用详解
- java中RMI远程调用详解
- coredump详解
- Gesture手势-------LeapMotion API
- UITableView 查询结果为空,显示无数据的方法
- 关于基于OPENCV摄像机标定的一点感受
- 每天思考一题
- Java RMI详解
- 七个你无法忽视的Git使用技巧
- 计算机网络4--Internet结构
- 第一行代码3.2 常见控件的使用方法
- 七个你无法忽视的Git使用技巧
- 数组-《数据结构1000》-练习题
- 数据库having和where的区别
- sqlserver decimal转换成int类型的转换出错的另一种解决办法
- 文章标题