`
lijj_72
  • 浏览: 21952 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Tuscany SCA软件架构设计理念分析(二)

阅读更多

Tuscany  SCA软件架构设计理念分析(二)

——动态代理模式和方法调用

李俊杰

1.     概述

上一篇文章主要讲述了Tuscany SCA的插件板模式及工厂模式的发展和提升,本文主要介绍Tuscany SCA开源软件中动态代理模式(Dynamic Proxy)及方法调用Invocation 。在使用Tuscany SCA中,我们只需要写接口及实现类,这些接口和实现类就是普通的java代码,并没有特殊之处。Tuscany SCA会根据“.composite”文件把这些信息组装成Compoiste,至于如何组装,则是Tuscany SCAAssembly模块的主要内容,我以后会介绍,但现在的问题是,如何来实现调用这些类的方法的问题,因为当调用的时候,外部接口是Tuscany SCADomainDomain依赖的Runtime中就加载有Composite的内容,客户的逻辑在应用程序(即interface implementClass),但这些都被组装进入了Composite中,所以要使用动态代理模式来实现,使得侵入性最小。<o:p></o:p>

2.     Java动态代理基础知识

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

InvocationHandler必须被实现,实现这个接口的invoke(Object obj,Method method, Object[] args),第一个参数obj一般是指代理类,method是被代理的方法, args为该方法的参数数组。这个invoke方法的内容主要是在调用被代理的方法前后方便地加上你自己的逻辑,如下例子

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(“
调用前你要插入的逻辑,如验证权限”);<o:p></o:p>

//实际调用被代理类的方法<o:p></o:p>

Object result = method.invoke(this.target,args);<o:p></o:p>

System.out.println(“调用后你要插入的逻辑,如调整系统状态”);<o:p></o:p>

  return result;
    }

     Proxy:该类即为动态代理类,是Jdk实现的类,你无须实现,只使用就行其中主要包含以下内容:

Proxy.newProxyInstance(ClassLoader,cls. Interfaces[],InvocationHandler)

其中ClassLoader是加载类,Inerface数组表示要代理的类的所有接口,InvocationHandler即上面介绍的具体实现类。通过这个方法就可以获取动态代理类Proxy,其实例是$proxy。如下例子表示如何使用动态代理:<o:p></o:p>

PersonImpl person = new PersonImpl(); //在这里指定被代理类<o:p></o:p>

 InvocationHandler ds = new DynamicSubject(person); //初始化代理类<o:p></o:p>

Class cls = person.getClass();<o:p></o:p>

<o:p> </o:p>

Person person1=Person.class.<o:p></o:p>

cast(Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),ds));<o:p></o:p>

person1.getName();<o:p></o:p>

上面的person1就是proxy对象,即动态代理,所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

另外动态生成proxy类有以下限制:接口数组中的每个元素应代表接口,不能表示类,或原始类型,不能出现重复的类型,接口可以通过名称访问到,两个接口不能存在方法名与参数列表相同但返回值不同的情况,最大数为65535动态代理只能够对interfaces进行动态的代理, 也就是说它先找出需要代理的对象实现的所有的interface, 然后只对所有的这些interface的所有的方法代理,对象除了interfaces以外的方法不予处理。这就是说我们再做contribution时,只要可以被外部调用的方法,都必须在接口中声明。

<o:p> </o:p>

3.   Tuscany SCA软件动态代理模式(Dynamic Proxy)及方法调用<o:p></o:p>

<o:p> </o:p>

根据以上的JDK动态代理基础知识介绍,下面介绍Tuscany SCA软件在动态代理和方法调用方面的设计。

(1) Tuscany SCA中动态代理模式的应用

基于上面的动态代理的知识,我们来看Tuscany SCA是如何设计的,首先来看一下它最核心的org.apache.tuscany.sca.core.invocation.JDKProxyFactory类的方法createProxy

public <T> T createProxy(CallableReference<T> callableReference) throws ProxyCreationException {<o:p></o:p>

        assert callableReference != null;<o:p></o:p>

        Class<T> interfaze = callableReference.getBusinessInterface();<o:p></o:p>

        JDKInvocationHandler handler = new JDKInvocationHandler(messageFactory, callableReference);<o:p></o:p>

        ClassLoader cl = interfaze.getClassLoader();<o:p></o:p>

        return interfaze.cast(Proxy.newProxyInstance(cl, new Class[] {interfaze}, handler));<o:p></o:p>

    }<o:p></o:p>

和上面介绍JDK Proxy的例子来看多么的相似,第一个参数是ClassLoader,第二个参数是要代理的类的接口数组,第三个参数是InvocationHandler,这儿是JDKInvocationHandler,如下图所示,浅蓝色标注的类就是我们核心工作类,由它来完成创建Proxy的任务。

<o:p> </o:p>

<v:shapetype o:spt="75" coordsize="21600,21600" filled="f" stroked="f" id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" o:connecttype="rect" gradientshapeok="t"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" o:ole="" style="WIDTH: 414.75pt; HEIGHT: 323.25pt"><v:imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.emz" o:title=""></v:imagedata></v:shape>

上面绿色的DefaultSCADomainSCA对外的接口类,在SCADomain接口下面的实现类,所有的外部操作都来自这个Domain,如何调用的呢

//创建SCADomain:扩展点注册器实例化,注册对象到扩展点注册器,加载ModuleActivator//解析策略配置文件definitions.xml,资源加载(资源查找,解析),资源组装(build, activate, start

SCADomain scaDomain = SCADomain.newInstance("Calculator.composite");       

//获取Service,在这儿通过SCADomain的对外接口来获取CalculatorService代理类“$Proxy

CalculatorService calculatorService =

            scaDomain.getService(CalculatorService.class, "CalculatorServiceComponent");

如上图所示,绿色的依赖线显示了调用的先后顺序。实例化后的DefaultSCADomain是对外部的总接口,其中有HashMap<String, Component>,以“CalculatorServiceComponent”获取对应的RuntimeComponentRuntimeComponent再获取RuntimeComponentContext,从而获取相关ServiceReference,从ServiceReference得到了ProxyFactory,这儿存在着一个代理模式,由DefaultProxyFactoryExtensionPoint类来创建真正的核心工作类JDKProxyFactory。然后由JDKProxyFactory创建Proxy。这儿的Proxy就是JDKInvocationHandler,就是这个类实现了InvocationHandler接口 ,如上面动态代理基础知识介绍,该类实现了invoke(Object proxy, Method method, Object[] args)方法。

(2)             EJB组件和SCA Component的异曲同工之道<o:p></o:p>

到这一步,其实就是我们有了需求,根据我们的请求,通过SCA的容器(请允许我这样讲,类似于Spring容器和Tapestry容器)获取动态代理对象。只不过绕了个弯,给人一种九曲回肠的感觉,为什么“以曲代直”,不直捣黄龙呢,就像我们MVC一样,分层的目的是解耦,同时可以无缝地插入一些东西。那么会插入什么东西呢,因为SCA是个SOA的基础框架,必须能够对付不同的语言,不同的平台,不同的网络协议,所以它必须封装这些内在的东西,展现给我们外部的仅仅是CompositeComponent ServiceReference,因此就会给人一种内部复杂,外部接口简单的感觉,也就是透明的感觉。

到了这儿,我想更深层次地介绍Component,类似于EJB功能的东东,但又不象EJB那样在内部做业务逻辑,并且需要继承某些固定的接口(RemoteLocal接口),而是把业务逻辑写在POJO(普通的interface class)中,通过配置文件把这些POJO组装起来(Assembly),形成Component的,进一步生成Composite,就相当于业务中的模块,对外提供服务(Service)。在SCADomain中就包含HashMap,其Value值就是组装好的Componentkey值为配置文件中的名称“CalculatorServiceComponent”,从而获取到组装好可用的ComponentRuntimeComponent),获取ProxyFactory,从ProxyFactory创建出能够实现代理的的Poxy。可以这样说SCADomain中包含着若干个Component,通过Component名称获取Componentcomponent得到Proxy,也就是ComponentSCA的核心概念。

从上面的论述中可以看出,Component实际上是个外壳,但外壳是包含很多底层功能,如安全(policy),网络协议(binding),上下文(context),RMI(远程调用),事务处理等等和业务无关的东西,类似于EJB容器的功能,只不过不象EJB那样依赖于EJB容器(应用服务器如weblogicwebsphere等),而是依赖于轻量级的Component,之所以这样说,是指Component的实现是基于IOC原理

SCA  Component是更高级别的抽象,同时也是更高级别的重用,是服务级别的,即业务级别的,而EJB更象是具体的增删改查操作,是较底层的计算机表现;Component的实现不象EJB必须用java实现,其他语言也支持,这就更能表现出Component是外壳,是容器。而真正的业务逻辑才是SOA开发人员要关注的问题,其他底层的功能都是依赖于配置文件。

(3) Tuscany  SCA中动态代理的方法调用

上面我们介绍了Proxy的获取九曲回肠之路,这个Proxy最后露出JDKInvokeHandler庐山真面目,那么是如何通过这个代理来进行方法调用呢?如下图所示,绿色的类JDKInvokeHandler是发起方法调用的起点,最终实现调用功能的是蓝色的类JavaImplementationInvoke,其方法调用的核心语句如下:

if (payload != null && !payload.getClass().isArray()) {

                ret = method.invoke(instance, payload);

            } else {

                ret = method.invoke(instance, (Object[])payload);

            }

结合前面动态代理基础知识,方法调用就是这么简单,invoke

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics