CSDN博客

img TomHornson

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

发表于2004/12/29 21:42:00  1285人阅读

                                         Java中,利用语言与平台特性改进RMI分布计算框架
                                              
                                                          TomHornson(@)hotmail.com
                                                                  于珞珈山

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

关键字:JavaRMIStub/SkeltonSerializationDynamicProxyDynamicClassLoading

Abstract

 

KeyWord

 

 

1        引言

 

1.1Java概述

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

 

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

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

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

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

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

 

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.classHelloWorldImpl.classMain.classClient.class

HelloWorldImpl_Stub.classHelloWorldImpl_Skel.class

2.1.6运行系统

服务器端首先配置文件HelloWorld.classHelloWorldImpl.classMain.class

HelloWorldImpl_Stub.classHelloWorldImpl_Skel.class文件,然后执行

javarimregistry

javaMain

客户端首先配置文件HelloWorld.classHelloWorldImpl_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事实上是代表StubRemoteObject。到此为止,我们已经取得了远程对象的远程引用。

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

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

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

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

 

3        几种Java语言特性

 

3.1   JavaSerialization特性

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

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

 

3.2   JavaDynamicClassLoading特性

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

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

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

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

 

3.3   JavaDynamicProxy特性

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,在客户端添加

ReconnectProxyPerformanceProxy。决定到底是否是客户端拦截器的是是否使用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-JavaEJB企业级应用开发.北京:机械工业出版社,2003.

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

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

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


0 0

相关博文

我的热门文章

img
取 消
img