一、前言
java编程语言设计之初就是面向对象和支持网络的,基于对象的rmi已内置java分布式系统平台中。对于tcp/ip网络编程,基于socket套接字进行编程展开,对于socket编程,需要把复杂的业务定义统一提交到该接口上,所以就会有大量的重复代码,在复杂的分布式系统计算中,容易出错,同时代码的维护难度比较大。需要实现快速、高效、安全、易扩展系统就变得追求和倡导的主题。Java RMI实现机理是基于代理的类加载器获取远程虚拟机内存中的对象,详情参见下方第五章节。
二、RMI简介
远程方法调用(Remote Method Invocation ,RMI),实现在不同的Java虚拟机(JVM)间对象间的通信,客户端(一个JVM)可以同步调用服务器(其它JVM)的对象的方法。作为rmi底层实现,会有很负责的Socket实现,对于用户只提供简单透明的对象调用方法接口,rmi基本结构包括三个抽象层,具体如下:
1、存根/框架层(Stubs/Skeletons Layer)
在基层上设计上,主要引入两大对象存根(Stub)和框架(Skeleton),当然在最底层基于tcp/ip协议将所有数据对象转化为字节流(byte stream),在基层层面上都是基于Proxy代理设计模型进行设计,stub代表远处客户方对象在本地的存根(调用映象),Skeleton类具体实现连接及stub通信,向远程服务实现参数实例化调用,并返回结果给到stub对象上,总而言之,Skeletons实现的整个框架设计的高内聚支持类,没有具体的业务设计关联
2、远程引用层(Remote Reference Layer)
远程引用层定义和配置支持RMI连接的调用语义(semantics)
进行远程访问调用需要用到远程调用协议JRMP(Java Remote Method Protocol),具体的调用对象方法包含在java.rmi.server包内
3、传输层(Transport Layer)
传输层在终端和服务端间建立基于流的网络连接,同时配置并管理这些连接
三、RMI开发步骤如下:
使用rmi编写c/s模式应用程序,主要包括以下6个步骤:
1.定义远程调用接口
2.实现远程接口
3.准备远程调用所设计的调用对象
4.生产存根对象stub和框架skeleton
5.用Rmiregistry找到远程对象
6.运行调试RMI应用接口
四、RMI示例代码
1.服务端代码包括主服务类Server.java、业务接口及实现类(Business.java、BusinessImpl.java)
Server类
import java.rmi.registry.LocateRegistry;@b@import java.rmi.registry.Registry;@b@import java.rmi.server.UnicastRemoteObject;@b@@b@/**@b@ * @author issuser@b@ *@b@ */@b@public class Server {@b@@b@ /**@b@ * @param args@b@ */@b@ public static void main(String[] args) throws Exception{@b@ // TODO Auto-generated method stub@b@ int port=9527;@b@ String name="BusinessDemo";@b@ Business business=new BusinessImpl();@b@ UnicastRemoteObject.exportObject(business,port);@b@ Registry registry=LocateRegistry.createRegistry(1099);@b@ registry.rebind(name, business);@b@@b@ }@b@@b@}
Business接口类
import java.rmi.Remote;@b@import java.rmi.RemoteException;@b@@b@public interface Business extends Remote {@b@@b@ public String echo(String message) throws RemoteException;@b@}
BussinessImpl接口实现类
import java.rmi.RemoteException;@b@@b@public class BusinessImpl implements Business {@b@@b@ @Override@b@ public String echo(String message) throws RemoteException {@b@ // TODO Auto-generated method stub@b@ if("quit".equalsIgnoreCase(message.toString())){@b@ System.out.println("Server will be shutdown!");@b@ System.exit(0);@b@ }@b@ System.out.println("Message from client:"+message);@b@ return "Server response:"+message;@b@ }@b@ @b@}
2.客户端调用类Client,同时也包括服务端映射Business接口类及BusinessImpl类
import java.rmi.registry.LocateRegistry;@b@import java.rmi.registry.Registry;@b@@b@public class Client {@b@@b@ public static void main(String[] args) throws Exception{@b@ // TODO Auto-generated method stub@b@ @b@ Registry registry=LocateRegistry.getRegistry("localhost");@b@ String name="BusinessDemo";@b@ Business business=(Business)registry.lookup(name);@b@ business.echo("hello ruirui");@b@ }@b@@b@}
1. 像上面4.2中客户端调用类java.rmi.registry.LocateRegistory类,从下图源码中可以看出代理工具类获取注册器对象
2. 然后找到对应的工具类源码sun.rmi.server.Util,可以看出其是由代理类通过类加载器找出远程对象
3. 然后通过代理映射类java.lang.reflect.Proxy,代理类原理通过加载器来实例化
4. 如上面4.2中通过java.rmi.registry.Registry类的lookup方法,如下图可以看出其实通过Hashtable存储查找