分布式对象技术及其应用_第1页
分布式对象技术及其应用_第2页
分布式对象技术及其应用_第3页
分布式对象技术及其应用_第4页
分布式对象技术及其应用_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

前言分布式对象技术是在面向对象技术的基础上发展起来的,他要解决的重要问题是位于不同进程中的对象之间的调用问题。在中间件系统、Web服务(WebService)以及SOA(ServiceOrientedArchitecture,面向服务架构)的研究与开发等许多重要领域,分布式对象技术都发挥着不可替代的作用。本书共有8章组成,按照循序渐进的原则,从理论到实践逐步介绍分布式对象技术的典型代表——CORBA的基本概念和设计规则,重要涉及CORBA的组成与解决流程、IDL接口定义语言、CORBA客户端程序设计与服务器程序设计以及动态接口等内容。第一章Java语言基础1.6委托解决与功能继承在java语言中只允许单一继承方式,也就是只允许有一个父类。这样,要运用多重继承的功能,就必须采用此外的手段,其中委托(delegation)解决方式是比较有效和常用的方法。例:1)一个简朴的堆栈类,用于对字符串进行管理ClassStringStack{ProtectedintstackLen; ProtectedintstackCount; ProtectedStringstack[]; //构造方法 StringStack(intlen){ stackLen=len; stackCount=0; stack=newString[stackLen]; } //数据进栈解决 Publicvoidpush(Stringdata){ If(stackCount>=stackLen){ System.out.println(“Stackoverflow.”); System.exit(1); } Stack[stackCount++]=data; } //数据出栈解决 PublicStringpop(){ If(stackCount>0){ Returnstack[--stackCount]; }else{ Return“Nodata”; } }}2)类KeyValue,用于对关键字极其所相应的值进行管理ClassKeyValue{ ProtectedintkeyLen; ProtectedintkeyCount; ProtectedStringKey[]; ProtectedStringValue[]; //构造方法 KeyValue(intlen){ keyLen=len; keyCount=0; Key=newString[keyLen]; Value=newString[keyLen];}//返回keyCountPublicintgetCount(){ ReturnkeyCount;}//存入key和valuePublicvoidaddKeyValue(Stringkey,Stringvalue){ If(keyCount<keyLen){ Key[keyCount++]=key; Value[keyCount]=value; keyCount++;}}//返回指定序号的keyPublicStringgetKey(intnumber){ ReturnKey[number];}//返回指定key的value值PublicStringKeyToValue(Stringkey){ For(inti=0;i<keyCount;i++){ If(Key[i].equals(key)){ ReturnValue[i]; } } Return“”;}}3)定义类StringStackWithKV,在该类中希望具有StringStack和KeyValue两个类的功能。如何实现?设计模式:代理模式代理模式定义:为其他对象提供一种代理以控制对这个对象的访问。ProxyPattenProvideasurrogateorplaceholderforanotherobjecttocontrolaccesstoit.1概述当用户希望和某个对象打交道,但程序也许不希望用户直接访问该对象,而是提供一个特殊的对象,这个特殊的对象被称作当前要访问对象的代理,程序让用户和对象的代理打交道,即让用户通过访问代理来访问想要访问的对象。在代理模式中,代理的特点是:它与所代理的对象实现了相同的接口,当用户请求代理调用这样的方法时,代理就把实际的方法调用委托给它所代理的对象,即让它所代理的对象调用同样的方法。比如,秘书是老板的代理,老板和秘书都有听电话的方法:herePhone()。公司规定用户必须先和秘书通电话才干和老板通电话,也就是说,用户必须一方面请求秘书调用herePhone(),当秘书确认老板可以接听电话时,就将用户的实际请求委派给老板,即让老板调用herePhone()方法。《ingerface》《ingerface》PhoneherePhone():voidVoidherePhone(){ System.out.println(“请稍等….”);//委托boss调用herePhone()boss.herePhone();}BossherePhone():voidSecretaryboss:BossherePhone():void 图:老板和秘书代理模式是为对象提供一个代理,代理可以控制对它所代理对象的访问。代理模式最常见的两种情况:远程代理和虚拟代理。2模式的结构和使用代理模式涉及三种角色:抽象主题(Subject):抽象的主题是一个接口,该接口是对象和它的代理所共用的接口,即是RealSubject角色和Proxy角色实例所实现的接口。实际主题(RealSubject):实际主题是实现抽象主题接口的类。实际主题的实例是代理角色(Proxy)实例所要代理的对象。代理(Proxy):代理是实现抽象主题接口的类(代理和实际主题实现了相同的接口)。代理具有主题接口声明的变量,该变量用来存放RealSubject角色的实例引用。例:求三角形面积3远程代理Java在RMI(RemoteMethodInvocation)中是如何使用代理模式的。RMI是一种分布式技术,使用RMI可以让一个虚拟机(JVM)上的应用程序请求调用位于网络上另一处JVM上的对象方法。习惯上称发出调用请求的虚拟机(JVM)为(本地)客户机,称接受并执行请求的虚拟机(JVM)为(远程)服务器。Java代理模式进一步理解代理模式对学习j2ee开源框架编程是至关重要的。1.代理模式

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目的对象之间起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:声明真实对象和代理对象的共同接口;

代理角色:代理对象角色内部具有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相称于对真实对象进行封装。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

以下以《Java与模式》中的示例为例:

代码://抽象角色:

abstractpublicclassSubject{

abstractpublicvoidrequest();

}

//真实角色:实现了Subject的request()方法。

publicclassRealSubjectextendsSubject{

publicRealSubject(){

}

publicvoidrequest(){

System.out.println("Fromrealsubject.");

}

}

//代理角色:

publicclassProxySubjectextendsSubject{

privateRealSubjectrealSubject;//以真实角色作为代理角色的属性

publicProxySubject(){

}

publicvoidrequest(){//该方法封装了真实对象的request方法

preRequest();

if(realSubject==null){

realSubject=newRealSubject();

}

realSubject.request();//此处执行真实对象的request方法

postRequest();

}

privatevoidpreRequest(){

//somethingyouwanttodobeforerequesting

}

privatevoidpostRequest(){

//somethingyouwanttodoafterrequesting

}

}

//客户端调用:

Subjectsub=newProxySubject();

Sub.request();

由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达成目的,同时还封装了其他方法(preRequest(),postRequest()),可以解决一些其他问题。

此外,假如要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须相应一个代理角色,假如大量使用会导致类的急剧膨胀;此外,假如事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

2.动态代理

Java动态代理类位于Java.lang.reflect包下,一般重要涉及到以下两个类:

(1).InterfaceInvocationHandler:该接口中仅定义了一个方法Object:invoke(Objectobj,Methodmethod,Object[]args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中重要包含以下内容:

ProtectedProxy(InvocationHandlerh):构造函数,估计用于给内部的h赋值。

StaticClassgetProxyClass(ClassLoaderloader,Class[]interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的所有接口的数组。

StaticObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

所谓DynamicProxy是这样一种class:它是在运营时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。(参见文献3)

在使用动态代理类时,我们必须实现InvocationHandler接口,以第一节中的示例为例:

代码://抽象角色(之前是抽象类,此处应改为接口):

publicinterfaceSubject{

publicvoidrequest();

}

//具体角色RealSubject:实现了Subject接口的request()方法。

publicclassRealSubjectimplementsSubject{

publicRealSubject(){

}

publicvoidrequest(){

System.out.println("Fromrealsubject.");

}

}

//代理角色:

importjava.lang.reflect.Method;

importjava.lang.reflect.InvocationHandler;

publicclassDynamicSubjectimplementsInvocationHandler{

privateObjectsub;

publicDynamicSubject(Objectsub){

this.sub=sub;

}

publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{

System.out.println("beforecalling"+method);

method.invoke(sub,args);

System.out.println("aftercalling"+method);

returnnull;

}

}

该代理类的内部属性为Object类,实际使用时通过该类的构造函数DynamicSubject(Objectsub)对其赋值;此外,在该类还实现了invoke方法,该方法中的"method.invoke(sub,args)"其实就是调用被代理对象的将要被执行的方法,方法参数sub是实际的被代理对象,args为执行被代理对象相应操作所需的参数。通过动态代理类,我们可以在调用之前或之后执行一些相关操作。

客户端:

代码:importjava.lang.reflect.InvocationHandler;

importjava.lang.reflect.Proxy;

importjava.lang.reflect.Constructor;

importjava.lang.reflect.Method;

publicclassClient{

staticpublicvoidmain(String[]args)throwsThrowable{

RealSubjectrs=newRealSubject();//在这里指定被代理类

InvocationHandlerds=newDynamicSubject(rs);//初始化代理类

Classcls=rs.getClass();

//以下是分解环节

/*

Classc=Proxy.getProxyClass(cls.getClassLoader(),cls.getInterfaces());

Constructorct=c.getConstructor(newClass[]{InvocationHandler.class});

Subjectsubject=(Subject)ct.newInstance(newObject[]{ds});

*/

//以下是一次性生成

Subjectsubject=(Subject)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds);

subject.request();

}

通过这种方式,被代理的对象(RealSubject)可以在运营时动态改变,需要控制的接口(Subject接口)可以在运营时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

3.代理模式使用因素和应用方面

(1)授权机制不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.

(2)某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动.

举例两个具体情况:

假如那个对象是一个是很大的图片,需要花费很长时间才干显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片解决完毕,这时需要做个图片Proxy来代替真正的图片.

假如那个对象在Internet的某个远端服务器上,直接操作这个对象由于网络速度因素也许比较慢,那我们可以先用Proxy来代替那个对象.

总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可认为我们节省很多宝贵的Java内存.所以,有些人认为Java花费资源内存,我认为这和程序编制思绪也有一定的关系.

(3)现实中,Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用远程代理让我们思考一下下面的代码://ClientclassCustomer{publicvoidsomeMethod(){//CreatetheServiceProviderInstanceFileUtilfutilObj=newFileUtil();//AccesstheServicefutilObj.writeToFile(“SomeData”);}}作为它实现的一部分,Customer类创建了一个FileUtil类的一个实例并且直接访问它的服务。换句话说,对于客户对象,访问FileUtil对象的方式是很直接的。它的实现也许是客户对象访问服务提供者对象最为普通的方式了。相比较,有些时候客户对象也许不直接访问服务提供者(也就是指目的对象),这种情况是由于下面的因素导致的:(1)目的对象的位置??目的对象也许存在于同一台或者不同机器的不同地址空间。(2)目的对象的存在形式??目的对象也许直到他被请求服务的时候还不存在,或者对象被压缩。(3)特殊的行为??目的对象可以根据客户对象的访问权限接受或拒绝服务。在多线程环境,一些服务提供者对象需要特殊的考虑。在这些情况下,代理模式(ProxyPattern)建议不要使有特殊需求的客户对象直接访问目的对象,而是使用一个单独的(分离的)对象(也就是指代理对象)为不同的客户提供通常的、直接的访问目的对象的方式。代理对象提供和目的对象同样的接口。代理对象负责与目的对象交互的细节,代表客户对象与目的对象交互。所以客户对象不再需要解决访问目的对象的服务时的特殊需求。客户对象通过它的接口调用代理对象,代理对象直接把这些调用依次地传递给目的对象。客户对象不需要知道代理的原对象(目的对象)。代理对象隐藏了与客户对象进行交互的对象细节,如:对象是否是远程的、是否初始化、是否需要特殊的权限等。换句话说,代理对象作为客户和不可访问的远程对象或推迟初始化对象之间的透明桥梁。代理对象因使用的场景不同,代理的种类也不同。让我们来快速的浏览一下一些代理和它们的目的。注意:表23.1列出了不同种类的代理对象,在这里仅讨论远程代理。在Java中,远程方法调用(RMI)充足的运用了远程代理模式,让我们快速的浏览一下远程方法调用(RMI)的概念和远程方法调用(RMI)通信过程应用的组件。RMI:快速浏览

RMI使客户对象像访问本地对象同样访问远程对象并调用其方法成为也许。下面是为实现RMI功能而一起协作的不同组件。(1)远程接口(RemoteInterface)??一个远程对象必须实现一个远程接口(这个接口扩展java.rmi.Remote)。远程接口声明可以被客户访问的远程对象的方法。换句话说,远程接口可以当作远程对象对客户的视图。需求(规定):1)扩展java.rmi.Remote2)在远程接口中定义的所有方法必须声明抛出java.rmi.RemoteException异常。(2)远程对象(RemoteObject)??远程对象负责实现在远程接口中定义的方法。需求(规定):1)必须提供远程接口的实现。2)必须扩展java.rmi.server.UnicastRemoteObject类。3)必须有一个没有参数的构造函数。4)必须与一个服务器相关联。通过调用零参数的构造函数,服务器创建远程对象的一个实例。(3)RMI注册表(RMIRegistry)??RMI注册表提供了保持不同远程对象的地址空间。1)远程对象需要存储在一个客户可以通过命名引用(Namereference)来访问它的RMI注册表中。2)一个给定的命名引用仅可以存储一个对象。(4)客户(Client)??客户是一个试图访问远程对象的应用程序。1)必须可以感知被远程对象实现的接口。2)通过命名引用(Namereference)在RMI注册表中可以查到远程对象。一旦查到远程对象的引用,调用这个引用上的方法。(5)RMIC(JavaRMI桩编译器)JavaRMIstubcompiler??一旦远程对象编译成功,RMIC(JavaRMI桩编译器)可以生成远程对象的桩类文献(stub)和框架类文献(skeleton)。桩类文献(stub)和框架类文献(skeleton)从编译的远程对象类中产生。这些桩类文献(stub)和框架类文献(skeleton)使客户对象以无缝的方式访问远程对象成为也许。下面这部分描述客户对象和远程对象如何通信。RMI通信机制:一般地,客户对象不能按通常方式直接访问远程对象。为了使客户对象像访问本地对象同样访问远程对象的服务,RMIC(JavaRMI桩编译器)生成的远程对象的桩文献(stub)和远程接口需要拷贝到客户机器上。桩文献(stub)负责扮演着远程对象的(远程)代理的角色,负责把方法的调用传递给真实的远程对象实现所在的远程服务器上。任何时候,客户对象引用远程对象,这个引用事实上是远程对象的本地桩文献。也就是,当客户调用远程对象上的方法时,调用一方面被本地桩实例所接受,桩再将这个调用传递到远程服务器上。在服务器端,RMIC产生的远程对象的框架文献(skeleton)接受这个调用。框架文献(skeleton)在服务器端,不需要拷贝到客户机器上。框架文献(skeleton)负责将这些调用转发到真正的远程对象的实现上。一旦远程对象执行了方法,方法返回的结果将按照反方向返回给客户。RMI和远程代理模式:从RMI通信的讨论中,可以看到桩类文献扮演着远程对象的远程代理的角色。它使得客户访问远程对象就像访问本地对象同样成为也许。因此,一些使用了RMI技术的应用就已经暗含着代理模式的实现。例子:在讨论外观模式时,我们建立了一个简朴的客户数据管理应用来验证和保存输入的客户数据。我们的设计由分别代表不同客户数据的三个类组成。在应用外观模式以前,客户AccountManager可以直接与子系统的三个用来验证、保存客户数据的类交互。应用外观模式,我们定义了一个CustomFacade外观对象代表客户与三个子系统类交互(如图23.3)。Figure23.3:CustomerDataManagementApplicationfortheLocalModeofOperation?ClassAssociation在这个应用中,子系统组件和外观对象对于客户对象AccountManager都是本地的。现在,让我们建立这个应用的不同版本,这个版本已远程的方式运营。在远程方式下,这个应用通过运用JAVARMI技术,访问远程对象。在使应用运营在远程操作模式下的设计中,我们要把子系统组件(Account、Address和CreditCard)和外观(CustomerFacade)移到远程服务器上。这样会带来以下好处:1)在服务器上的对象可以被不同的客户应用所共享。客户不再需要维护这些类的本地版本,因此,成为轻型客户端(light-weighted)。2)可以对变化、性能和监控进行统一的集中控制。Figure23.4:CustomerDataManagementApplicationfortheRemoteModeofOperation?ClassAssociation让我们开始运用RMI技术设计远程操作模式下的客户数据管理应用。第一步,先定义远程接口CustomerIntr:这个借口要满足:1)声明外观实现的方法。2)所有的方法声明抛出RemoteException异常。3)扩展java.rmi.Remote接口。publicinterfaceCustomerIntrextendsjava.rmi.Remote{voidsetAddress(StringinAddress)throwsRemoteException;voidsetCity(StringinCity)throwsRemoteException;voidsetState(StringinState)throwsRemoteException;voidsetFName(StringinFName)throwsRemoteException;voidsetLName(StringinLName)throwsRemoteException;voidsetCardType(StringinCardType)throwsRemoteException;voidsetCardNumber(StringinCardNumber)throwsRemoteException;voidsetCardExpDate(StringinCardExpDate)throwsRemoteException;booleansaveCustomerData()throwsRemoteException;}让我们重新定义CustomerFacade外观类,由于它要实现CustomerIntr远程接口。不同的客户对象通过CustomerIntr接口在具体类CustomerFacade上的实现与子系统对象进行交互。图23.5展示了CustomerFacade和它实现的远程接口CustomerIntr之间的结构和关联。Listing23.1:CustomerFacadeClass?RevisedpublicclassCustomerFacadeextendsUnicastRemoteObjectimplementsCustomerIntr{privateStringaddress;privateStringcity;privateStringstate;privateStringcardType;privateStringcardNumber;privateStringcardExpDate;privateStringfname;privateStringlname;publicCustomerFacade()throwsRemoteException{super();System.out.println("Serverobjectcreated");}publicstaticvoidmain(String[]args)throwsException{Stringport="1099";Stringhost="localhost";//Checkforhostnameargumentif(args.length==1){host=args[0];}if(args.length==2){port=args[1];}if(System.getSecurityManager()==null){System.setSecurityManager(newRMISecurityManager());}//CreateaninstanceoftheserverCustomerFacadefacade=newCustomerFacade();//BinditwiththeRMIRegistryNaming.bind("//"+host+":"+port+"/CustomerFacade”,facade);System.out.println("ServiceBound…");}publicvoidsetAddress(StringinAddress)throwsRemoteException{address=inAddress;}publicvoidsetCity(StringinCity)throwsRemoteException{city=inCity;}publicvoidsetState(StringinState)throwsRemoteException{state=inState;}publicvoidsetFName(StringinFName)throwsRemoteException{fname=inFName;}publicvoidsetLName(StringinLName)throwsRemoteException{lname=inLName;}publicvoidsetCardType(StringinCardType)throwsRemoteException{cardType=inCardType;}publicvoidsetCardNumber(StringinCardNumber)throwsRemoteException{cardNumber=inCardNumber;}publicvoidsetCardExpDate(StringinCardExpDate)throwsRemoteException{cardExpDate=inCardExpDate;}publicbooleansaveCustomerData()throwsRemoteException{AddressobjAddress;AccountobjAccount;CreditCardobjCreditCard;/*clientistransparentfromthefollowingsetofsubsystemrelatedoperations.*/booleanvalidData=true;StringerrorMessage="";objAccount=newAccount(fname,lname);if(objAccount.isValid()==false){validData=false;errorMessage="InvalidFirstName/LastName";}objAddress=newAddress(address,city,state);if(objAddress.isValid()==false){validData=false;errorMessage="Invalid}objCreditCard=newCreditCard(cardType,cardNumber,cardExpDate);if(objCreditCard.isValid()==false){validData=false;errorMessage="InvalidCreditCardInfo";}if(!validData){System.out.println(errorMessage);returnfalse;}if(objAddress.save()&&objAccount.save()&&objCreditCard.save()){returntrue;}else{returnfalse;}}}Figure23.5:FaçadeDesign?RemoteModeofOperation由于子系统组件对于CustomerFacade类是本地的,子系统组件初始化、方法调用的方式上没有任何变化,子系统组件对于CustomerFacade类仍然是本地对象。当执行的时候,CustomerFacade自己创建一个实例并把引用名称(referencename)保存在RMI注册表中。客户对象通过引用名称能取得远程对象的一个拷贝。由于客户不需要直接访问任何的子系统组件。所以在远程操作模式下的设计中,不需要对子系统的任何组件进行任何的修改。让我们重新设计客户类AccountManager:Listing23.2:AccountManagerClass?Revised……publicvoidactionPerformed(ActionEvente){……if(e.getActionCommand().equals(AccountManager.VALIDATE_SAVE)){//getinputvaluesStringfirstName=objAccountManager.getFirstName();StringlastName=objAccountManager.getLastName();Stringaddress=objAccountManager.getAddress();……try{//CallregistryforAddOperationfacade=(CustomerIntr)Naming.lookup("rmi://"+objAccountManager.getRMIHost()+":"+objAccount

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论