分享
 
 
 

Java中,利用语言与平台特性改进RMI分布计算框架

王朝java/jsp·作者佚名  2006-01-30
窄屏简体版  字體: |||超大  

摘要:RMI是Sun设计的优秀的基于Java的分布计算框架,像CORBA、DCOM等架构一样采用了经典的Stub/Skeleton设计。本文针对基于RMI企业级分布计算的实际需要,利用Java的特性,对RMI进行改进,设计出一个优秀的Intercepto(拦截器)-RMI框架。

关键字:Java;RMI;Stub/Skelton;Serialization;DynamicProxy;DynamicClassLoading

Abstract:

KeyWord:

1 引言

1.1Java概述

严格来说,Java指JavaPlatform,包括JVM(JavaVirtualMachine)、Java语言、Java核心类库和扩展类库及基于此平台的所有应用,它是由SunMicroSystems公司创造并领导发展的。凭借JVM承诺的“Writeonce,RunEverywhere”和垃圾回收、Java语言本身设计的先进、Java类库的强大和高效、SunMicroSystems适当的开放和约束规范,Java无疑已经成为当今最为流行的软件技术,在芯片制造、智能家电、手持智能商务设备、无线通信、个人电脑应用、企业应用系统架构,甚至是搜索引擎开发、军用系统开发、航天控制系统开发等领域都可见其活跃的身影。没有特别说明,下文中的Java特指Java语言。遵循”Networkiscomputer”和”Wemakethenetwork”理念,Sun将Java定位于”网络时代的语言“,因此Java中处处可见针对network的设计。譬如严格的数据类型定义、对象序列化、代码移动性、强大和方便的网络API、完整的安全体系结构等等,这些特性完全颠覆了传统的网络编程模型,一切变得简单而强大。

1.2 经典的Stub/Skeleton计算架构和RMI(RemoteMethodInvocation)

至今为止,几乎所有的分布式计算框架都采用了Stub/Skelton设计,如OMG的CORBA、

MicroSoft的DCOM、SunMicroSystems的RMI,以“通明化“远程调用。动作序列一般如下:客户端的远程调用”代理“给Stub,Stub与客户端分布计算引擎交互,客户端的引擎与服务器端的引擎通信,传递调用信息,服务器端的分布计算引擎与Skeleton交互,Skeleon将远程调用转发给远程对象实施。然后,再沿相反的路径传回结果。(图1)

RMI(RemoteMethodInvocation)是Sun设计的基于Java的轻量级分布对象计算解决方案。

RMI不但在本身的体系结构设计上非常优秀,它还利用和继承了Java平台的若干得天独厚的特性,譬如平台无关性、(分布)垃圾回收、安全性、代码移动性、类动态加载等等。它是EJB和JINI的分布特性支持技术。

2 RMI的编程模型和本质

2.1RMI的编程模型

2.1.1定义远程接口

publicinterfaceHelloWorldextendsRemote{

publicStringreturnGreeting(Stringparam)throwsRemoteException;

}

这个接口定义了远程对象行为,RMI规范规定远程接口需要直接或间接扩展Remote接口

并且方法签名需要抛出RemoteException异常。

2.1.2实现远程接口

publicclassHelloWorldImplextendsUnicastRemoteObjectimplementsHelloWorld{

publicHelloWorldImpl()throwsRemoteException{super();}

publicStringreturnGreeting(Stringparam){

return“Hello”+param;

}

}

2.1.3服务器端(Main.java)生成远程对象,并利用registry将之与一定的名字绑定。

/*…………*/

HelloWorldImplhwi=newHelloWorldImpl();

Naming.bind(“HelloWorld”,hwi);

/*…………*/

2.1.4创建客户端(Client.java)

/*…………*/

System.setSecurityManager(newRMISecurityManager());

HelloWorldhw=(HelloWorld)Naming.lookup(“rmi://localhost/HelloWorld”);

System.out.println(hw.returnGreeting(“World”));

/*…………*/

2.1.5编译源代码

javacHelloWorld.javaHelloWorldImpl.javaMain.javaClient.java

产生文件HelloWorld.class、HelloWorldImpl.class、Main.class、Client.class、

HelloWorldImpl_Stub.class、HelloWorldImpl_Skel.class。

2.1.6运行系统

服务器端首先配置文件HelloWorld.class、HelloWorldImpl.class、Main.class、

HelloWorldImpl_Stub.class、HelloWorldImpl_Skel.class文件,然后执行

javarimregistry

javaMain

客户端首先配置文件HelloWorld.class、HelloWorldImpl_Stub.class然后执行

javaClient

2.2RMI的本质

这里我们以上面叙述编程模型时使用的实例来描述追踪RMI的运作,从而探出本质。

2.2.3服务器(Main.java)中,

HelloWorldImplhwi=newHelloWorldImpl();

Naming.bind(“HelloWorld”,hwi);

上面两句,实现了远程对象的导出(export),并将之与名字HelloWorld绑定。

这里我们需要深入探讨,直入本质,因为我们的改进的一部分就是在这里着手的。因为HelloWorldImpl继承了UnicastRemoteObject,而UnicastRemoteObject在构造函数中通过

exportOjbet将对象导出到特定端口,以使得对象可被远程引用。ExportObject将远程对象置入一个ObjectTable中,并且加载HelloWorldImpl_Stub,并且将Stub与名字绑定。而不是一般认为的远程对象。这样作的目的主要是考虑到远程对象作为参数或返回值的时候,只能传入Stub,而不能移动远程对象实体,满足分布式环境计算的需要。

2.2.2客户端(Client.java)中,HelloWorldhw=

(HelloWorld)Naming.lookup(“rmi://localhost/HelloWorld”)解析。自然,在使用远程对象之

前,需要获得远程对象引用。这一步是通过registry来实现的,registry事实上,是rmi专

用的名字服务工具。它也是远程对象,默认运作在2009端口,也可以使用

LocateRegistry.createRegistry()在特定端口导出它。客户端的lookup操作会首先取得服

务器端registry的远程引用,然后使用远程引用再查询HelloWorldImpl,从服务器端获得的远程引用事实上是一个Stub,所以我们上面的hw事实上是代表Stub的RemoteObject。到此为止,我们已经取得了远程对象的远程引用。

2.2.3客户端(Client.java)中hw.returnGreeting(“World”)解析。客户端使用远程引用调用方法,作为Stub/Skeleton的经典步骤,客户端的调用“代理“给Stub,可以在HelloWorldImp_Stub.java中看到ref.invoke(this,_fld$method_hit_0,null,

0x9339f0d6bc98fe87L),然后Stub与JRMP引擎交互,由JRMP引擎来负责编组(返回时自然就是解列)远程引用,调用方法,方法参数等,并与服务器端JRMP通信,传递调用相关信息。服务器端JRMP引擎将获得的信息递交给Skeleton,Skeleton负责解列,并且从ObjectTable中获得远程对象,将调用“分发“给它执行

,HelloWorldImp_Skel.java中可见publicvoiddispatch(Remoteremote,RemoteCallremotecall,inti,longl),然后编组返回结果,沿相反的途径回传到客户端。

上面已经基本将核心步骤讲述了。可以参看图2。

3 几种Java语言特性

3.1 Java的Serialization特性

Serialization特性是在JDK1.1中增添的,一个对象只要implementsSerializable,

就可以实现”持久化”。持久化能力表示对象可以写入介质,然后再从介质中读出并在内存中恢复原状态的能力。对象的这种能力对于网络应用非常的重要。因为它可以支持对象在网络传输过程中,屏蔽系统的差异。我们关注的是接口中的ANY-ACCESS-MODIFIERObjectreadResolve()throwsObjectStreamException方法,它是用于在对象反序列化时,如果你希望用其它的对象来替代原先的对象,你就可以在这里实施。

3.2 Java的DynamicClassLoading特性

这就是所谓的“代码移动”基础。它是Java最大的特色之一。它允许代码从网络下

载执行。经典的应用是著名的Applet。Java类库中相关类的继承树为:java.lang.Object->

java.lang.ClassLoader->java.security.SecureClassLoader->java.net.UrlClassLoader和

java.lang.Object->java.rmi.server.RmiClassLoader。ClassLoader提供多种形式的类加载功能,特别是基于网络获得字节流,在本地从新映射类定义并加载的能力。UrlClassLoader提供基于网络url集的类加载。RmiClassLoader提供了一个statci功能函数集,一般由RmiRuntime使用以在Rmi编组解列时实现注释类路径信息、基于网络的类加载等等特性。

3.3 Java的DynamicProxy特性

DynamicProxy特性是在JDK1.3中添加的,它遵循Proxy模式的思想。一个Dynamci

Proxy可“代理”一组interface的实现,并且将实际方法调用代理给一个

InvocationHandler实施。通过这种特性,我们可以方便的实现很多经典的应用,如为一

组对象提供一个入口,从而实现在不改变类设计的情况下增加新的功能或者实现拦截

器等等。

4 利用上述Java特性改进RMI模型实施

就目前来说,RMI解决方案一般作为企业分布架构的基础。当然,企业级应用中,安全性、事务性、系统日记等性征都是很必要的,那么我们就设想是否可以在RMI层实施这些特性,从而建立设计更优秀、功能更强大、扩展性更强、维护更方便的企业级系统。经过探索,利用上述Java特性我们实现了这一构想,设计出Interceptor(拦截器)-RMI框架。图3

需要解决的核心问题和相应的解决方案如下:

1. 为了客户端从服务器端下载Stub并能够安装拦截器,我们需要替换掉服务器端默认的

类加载器,用DynamicClassLoader替代。

publicclassDynamicClassLoaderextendsURLClassLoader{

/*…………*/

protectedClassfindClass(Stringname)throwsClassNotFoundException{

if(name.endsWith("_Stub")){

name=name.substring(0,name.length()-5);

Classcl=loadClass(name);

currentClass.set(cl.getInterfaces()[0]);

returnDynamicRemoteStub.class;

}else{returnsuper.findClass(name);}

}

这样,我们在加载远程对象的时候,可以使用自己的ClassLoader,来动态替换Stub。

2.那么DynamicRemoteStub是什么呢?

publicclassDynamicRemoteStubextendsRemoteStub{

/*…………*/

ObjectreadResolve()throwsObjectStreamException

{

if(cl==null)returnthis;

DynamicStubHandlerstubHandler=newDynamicStubHandler();

Objectproxy=Proxy.newProxyInstance(cl.getClassLoader(),

newClass[]{cl},

stubHandler);

stubHandler.setProxy(this);

cl=null;

returnproxy;

}

}

这里我们需要注意的是readResolve,它是在对象序列化的时候调用,实施一定的方法,用其它的对象来代替原来解序列的对象。我们在这里实施这一行为返回代理,在于为客户端添加拦截器。

3.那么代理的处理者InvocationHandler是什么?就是DynamicStubHandler:

publicclassDynamicStubHandlerimplements

InvocationHandler,java.io.Serializable{

/*…………*/

//InvocationHandlerimplementation

publicObjectinvoke(Objectproxy,

Methodmethod,

Object[]args)throwsThrowable{

returnstub.getRef().invoke(stub,method,args,getHash(method));

}

}

/*…………*/

我们可以看到,returnstub.getRef().invoke(stub,method,args,

getHash(method)),通过它,客户端在经过任意个拦击器调用后,最后实施将远程对象的调用。

4.服务器端的拦截器实施。

HelloWorldhw=newHelloWorldImpl();

UnicastRemoteObject.exportObject(hw);

hw=(HelloWorld)Proxy.newProxyInstance(HelloWorld.class.getClassLoader(),

newClass[]{HelloWorld.class},

newLogProxy(hw));

UnicastRemoteObject.exportObject(hw);

/*…………*/

hw=(HelloWorld)Proxy.newProxyInstance(hw.getClass().getClassLoader(),

newClass[]{HelloWorld.class},

newReconnectProxy(server,HelloWorld.NAME));

hw=(HelloWorld)Proxy.newProxyInstance(HelloWorld.getClass().getClassLoader(),

newClass[]{HelloWorld.class},

newPerformanceProxy(hw));

Naming.bind(HellotWorld.NAME,server);

上面仅为示例,我们在打算在服务器端添加一个LogProxy,在客户端添加

ReconnectProxy和PerformanceProxy。决定到底是否是客户端拦截器的是是否使用UnicastRemoteObject.exportObject导出远程对象,因为RMI规范规范没有将Stub与名字绑定的对象,在远程引用的时候,直接将远程对象自身序列化到客户端,而不是它的Stub,这里实施了一个Trick。

5. 我们可以看到上面使用了大量的拦截器。事实上,拦截器主要的功能就是实施特殊应

需求,并且传递调用。最基本的要求,它们需要继承InvocationHandler,并且

implementsSerializable。

LogProxy示例:

publicclassLogProxyimplementsInvocationHandler,java.io.Serializable,LinkedProxy

{

/*…………*/

publicObjectinvoke(Objectproxy,

Methodmethod,

Object[]args)throwsThrowable{

/**

省略:具体的LogProxy拦截器行为在这里实施

**/

try{

returnmethod.invoke(next,args);

}catch(InvocationTargetExceptione){

throwe.getTargetException();

/**省略:next相关的操作**/

}}}

5 结语:改进的意义和应用

RMI作为目前最为优秀的分布计算框架之一,应用非常广泛,特别是企业级的系统基础架构。

而企业级架构中事务特性、日记、性能评价、设计上优秀的扩展性、网络范围管理的便利等等都是很必要的。Interceptor-RMI框架正是为了适应了这一需求而设计的。它为企业分布计算基础架构提供了一个优秀的参考。

参考文献

[1]SunMicroSystems,inc.RMISpecification[R].SunMicroSystems,2003.

[2]W.KeithEdwards.JINI核心技术.北京:机械工业出版社,2000.

[3]EdRoman,ScottAmbler.精通EJB[M].北京:电子工业出版社,2002.

[4]MarkoBoger.Java与分布式系统[M].北京:机械工业出版社,2003.

[5]Rickard?berg.精通RMI-Java与EJB企业级应用开发.北京:机械工业出版社,2003.

[6]朱刚等.Linux网络编程.北京:科学出版社,2000.

[7]DonBox.COM本质论.北京:中国电力出版社,2002.

[8]何炎祥,陈莘萌.Agent和多Agent系统的设计和应用.武汉:武汉大学出版社,2001.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有