<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Terry.Li-彬

    虛其心,可解天下之問;專其心,可治天下之學(xué);靜其心,可悟天下之理;恒其心,可成天下之業(yè)。

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks
    Java 2平臺1.3版本為Java映像API(Reflection API)增加了一個極其實(shí)用的擴(kuò)展:動態(tài)代理類。一個動態(tài)代理類就是一個實(shí)現(xiàn)了一系列運(yùn)行時指定的接口的類。這個代理可以象它真正實(shí)現(xiàn)了這些接口一樣使用。換句話說,可以直接在代理對象上調(diào)用任意接口的任意方法——當(dāng)然,必須先進(jìn)行必要的類型定型(casting)。由此,我們可以用動態(tài)代理類為一組接口創(chuàng)建一個類型安全的代理對象,且不必象使用編譯時工具一樣預(yù)先生成代理(有關(guān)動態(tài)代理類更詳細(xì)的說明,請參見本文最后的參考資源)。

    接下來我將介紹一個以動態(tài)代理類為基礎(chǔ)的框架,這個框架使得SOAP(簡單對象訪問協(xié)議)客戶程序的創(chuàng)建更加簡單和直觀。SOAP是一種用XML編碼數(shù)據(jù)的有線協(xié)議。在本系列文章的第二篇、第三篇構(gòu)造SOAP服務(wù)的過程中,我們發(fā)現(xiàn)客戶程序的開發(fā)者必須多做許多原來不必做的工作。為幫助回憶,你可以看一下第二篇文章中的SOAP服務(wù)代碼,看看和客戶程序代碼相比較時,服務(wù)程序的SOAP代碼是多么微不足道。本系列文章前幾篇所創(chuàng)建的簡單SOAP服務(wù)顯示出,基于SOAP的服務(wù)只包含無論用不用SOAP都必須提供的代碼。服務(wù)程序的開發(fā)者要編寫的額外代碼很少,而客戶程序開發(fā)者卻有許多額外工作要做。本文介紹的類將把這些額外工作減到最少。

    一、介紹SOAP代理類
    首先,我要給出如果客戶程序使用了本文創(chuàng)建的框架,它將變成什么樣子:

    package hello;
    import soapproxy.*;
    public class Client
    {
    public static void main(String[] args)
    {
    try
    {
    Class[] interfaces = new Class[] {hello.Hello.class};
    Hello hello = (Hello)(Proxy.newInstance("urn:Hello",interfaces));

    // 調(diào)用sayHelloTo方法
    // 這個sayHelloTo方法需要一個字符串參數(shù)
    System.out.println(hello.sayHelloTo("John"));

    // 調(diào)用sayHelloTo方法
    // 這個sayHelloTo方法需要一個Name JavaBean參數(shù)
    Name theName = new Name();
    theName.setName("Mala");
    System.out.println(hello.sayHelloTo(theName));
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
    }
    }


    也許是出于我的個人愛好,我認(rèn)為上面的客戶代碼比第二篇和第三篇文章中的客戶代碼更好。如果你現(xiàn)在不能理解上面的代碼,這很正常,但我想待到本文結(jié)束時你會理解的。

    要理解客戶程序的代碼,你必須深入了解SOAP Proxy類,它在soapproxy包內(nèi),可以在Proxy.java內(nèi)找到(參見本文最后的參考資源)。Proxy類有一個私有的構(gòu)造函數(shù),它意味著Proxy實(shí)例不能從Proxy之外創(chuàng)建;新建Proxy實(shí)例的唯一方法是通過靜態(tài)的newInstance()方法。newInstance()方法有兩個參數(shù):SOAP服務(wù)的對象ID,以及一個數(shù)組,數(shù)組中包含一組該代理要實(shí)現(xiàn)的接口的名字。對象ID很簡單,但這些接口名字是什么?從哪里去得到這些接口的名字?SOAP服務(wù)的開發(fā)者直接把服務(wù)上所有可被客戶程序調(diào)用的方法堆在一起得到一個接口。相當(dāng)簡單,不是嗎?

    現(xiàn)在我們?yōu)镠elloWorld服務(wù)定義一個接口。第二篇文章中,這個服務(wù)的最終版本有sayHelloTo()方法的兩個重載版本:一個版本的參數(shù)是一個字符串,另一個版本的參數(shù)是一個Name JavaBean。這兩個方法就可以構(gòu)成一個接口,稱為Hello,如下所示:

    package hello;
    public interface Hello
    {
    public String sayHelloTo(String name);
    public String sayHelloTo(Name name);
    }

    服務(wù)開發(fā)者決定要創(chuàng)建多少接口,以及為這些接口取什么樣的名字。例如,你可以為HelloWorld服務(wù)創(chuàng)建兩個接口,每一個接口包含一個方法。一般地,你應(yīng)該避免創(chuàng)建方法數(shù)量大于七個的接口。另外,注意只把那些看來有必要放在一起的方法用一個接口組織起來。例如,如果HelloWorld服務(wù)還有一個返回定制的Good-Bye消息給調(diào)用者的sayByeTo()方法,設(shè)計兩個獨(dú)立的接口也許比較明智:一個接口用于sayHelloTo()方法,一個接口用于sayByeTo()方法。

    現(xiàn)在我們有了定義HelloWorld服務(wù)和客戶程序之間契約的接口,下面返回來看newInstance()方法。如前所述,newInstance()方法創(chuàng)建Proxy類的一個新實(shí)例。newInstance()方法可以創(chuàng)建新實(shí)例是因為它屬于Proxy類,能夠訪問私有的構(gòu)造函數(shù)。newInstance()方法為新創(chuàng)建的實(shí)例調(diào)用initialize()方法。initialize()值得關(guān)注,因為動態(tài)代理就是在這里創(chuàng)建和返回。initialize()的代碼如下所示:

    private Object initialize(Class[] interfaces)
    {
    return(java.lang.reflect.Proxy.newProxyInstance(getClass().getClassLoader()
    ,interfaces,this));
    }

    注意newProxyInstance()方法的應(yīng)用。創(chuàng)建動態(tài)代理類實(shí)例的唯一辦法是調(diào)用該類(即java.lang.reflect.Proxy類)靜態(tài)的newProxyInstance()方法。java.lang.reflect.Proxy類為創(chuàng)建動態(tài)代理類提供了靜態(tài)方法,而且它還是所有由這些方法創(chuàng)建的動態(tài)代理類的超類。換句話說,它不僅是一個創(chuàng)建動態(tài)代理類的工廠,而且它本身也是一個動態(tài)代理類!因此,在我們的例子中,SOAP代理不是動態(tài)代理;相反,這個動態(tài)代理實(shí)際上是newProxyInstance靜態(tài)方法返回的java.lang.reflect.Proxy類的一個實(shí)例。從本文后面可以看到,這個動態(tài)代理實(shí)際上通過SOAP代理實(shí)現(xiàn)的invoke()方法完成它的所有工作。那么,這個動態(tài)代理如何建立和SOAP代理的聯(lián)系呢?因為有一個對SOAP代理的引用傳遞給了newProxyInstance()方法。也許現(xiàn)在這聽起來有點(diǎn)費(fèi)解,但只要你分析一下invoke()方法,這一切就很明白了。

    java.lang.reflect.Proxy類構(gòu)造函數(shù)的第一個參數(shù)是一個類裝載器實(shí)例,第二個參數(shù)是需要動態(tài)實(shí)現(xiàn)的接口的數(shù)組(它就是客戶程序傳遞給newInstance()的數(shù)組),第三個參數(shù)是一個實(shí)現(xiàn)了java.lang.reflect.InvocationHandler接口的類的實(shí)例。因為SOAP Proxy類實(shí)現(xiàn)了InvocationHandler接口,所以第三個參數(shù)是代理實(shí)例本身(即this)。InvocationHandler接口有一個方法invoke()。當(dāng)動態(tài)代理的動態(tài)實(shí)現(xiàn)的接口被調(diào)用時,Java運(yùn)行時環(huán)境調(diào)用invoke()方法。因此,舉例來說,當(dāng)客戶程序調(diào)用動態(tài)代理的Hello接口的sayHelloTo()方法時,Java運(yùn)行時環(huán)境將調(diào)用SOAP代理的invoke()方法。

    你可能已經(jīng)發(fā)現(xiàn),SOAP代理的newInstance()方法不返回SOAP代理的實(shí)例;相反,它返回newInsance()剛剛創(chuàng)建的動態(tài)代理,而動態(tài)代理動態(tài)地實(shí)現(xiàn)客戶程序傳入的接口數(shù)組??蛻舫绦蚩梢詫⑦@個返回的動態(tài)代理定型為傳入newInstance()的任意接口類型,在動態(tài)代理上調(diào)用接口所定義的各個方法,就象動態(tài)代理真地實(shí)現(xiàn)了那些接口一樣。

    .
    .
    try
    {
    Class[] interfaces = new Class[] {hello.Hello.class};
    Hello hello = (Hello)(Proxy.newInstance("urn:Hello",interfaces));
    // 調(diào)用參數(shù)為字符串的sayHelloTo方法
    System.out.println(hello.sayHelloTo("John"));
    // 調(diào)用參數(shù)為Name JavaBean的sayHelloTo方法
    Name theName = new Name();
    theName.setName("Mala");
    System.out.println(hello.sayHelloTo(theName));
    }
    .
    .

    在上面的代碼中,invoke()方法將被調(diào)用兩次,每次調(diào)用sayHelloTo()方法時執(zhí)行一次。現(xiàn)在我們來看看invoke()方法。簡而言之,invoke()方法的工作正是第二篇文章中每一個客戶程序必須手工完成的工作,其中包括:用合適的調(diào)用參數(shù)設(shè)置一個Call對象,定制的調(diào)用參數(shù)所需要的類型映射。由于SOAP代理中的invoke()方法擔(dān)負(fù)了所有這些任務(wù),客戶程序釋放了這份負(fù)擔(dān)。

    在invoke()方法接收到的三個參數(shù)中,我們只對后面兩個感興趣。第二個參數(shù),即Method對象,給出了被調(diào)用方法的名字。記住,被調(diào)用方法的名字對應(yīng)著一個SOAP服務(wù)導(dǎo)出的已知方法。服務(wù)的對象ID作為參數(shù)傳遞給newInstance()方法,所以invoke()方法已經(jīng)擁有該對象ID。invoke()方法利用這些信息,按照如下方式設(shè)置Call對象:

    Call call = new Call();
    call.setTargetObjectURI(urn);
    call.setMethodName(m.getName());
    call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);

    現(xiàn)在要做的是為遠(yuǎn)程服務(wù)調(diào)用設(shè)置參數(shù)。為此,我們要用到invoke()方法的第三個參數(shù):傳入動態(tài)代理上被調(diào)用方法的一個參數(shù)數(shù)組。數(shù)組中索引為0的參數(shù)是方法調(diào)用中最左邊的參數(shù),索引為1的參數(shù)是方法的第二個參數(shù),依此類推。舉例來說,如果客戶程序調(diào)用了sayHelloTo(String name)方法,那么參數(shù)數(shù)組就是包含一個字符串的數(shù)組。invoke()方法處理該數(shù)組的每一個元素,創(chuàng)建一個由Parameter對象構(gòu)成的向量(Vector)(正如第二篇文章中客戶程序所做的那樣):

    java.util.Vector params = new java.util.Vector();
    for( int i=0; i&lt;args.length; i++ )
    {
    if( isSimple(args[i]) || isSimpleArray(args[i]) )
    {
    params.add(new Parameter(_paramName+(i+1),
    args[i].getClass(),args[i],null));
    }
    else if( isVector(args[i]) )
    {
    addMapping((java.util.Vector)args[i]);
    params.add(new
    Parameter(_paramName+(i+1),args[i].getClass(),args[i],null));
    }
    // 如果這個數(shù)組的元素不屬于Java基本數(shù)據(jù)類型
    // 則假定這是一個JavaBean的數(shù)組
    else if( isArray(args[i]) )
    {
    if( smr == null )
    smr = new SOAPMappingRegistry();
    if( beanSer == null )
    beanSer = new BeanSerializer();

    ArraySerializer arraySer = new ArraySerializer();
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,
    null, null, beanSer, beanSer);
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,
    null,args[i].getClass(), arraySer, arraySer);
    params.add(new Parameter(_paramName+(i+1),
    args[i].getClass(),args[i],null));
    }
    // 假定這是一個Bean
    else
    {
    if( smr == null )
    smr = new SOAPMappingRegistry();
    if( beanSer == null )
    beanSer = new BeanSerializer();
    String qnamePart = args[i].getClass().getName();
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,
    new QName(urn, qnamePart),args[i].getClass(), beanSer,
    beanSer);
    params.add(new Parameter(_paramName+(i+1),args[i].getClass(),args[i],null));
    }
    }


    invoke()方法用到了許多私有的輔助方法,比如用isSimple()來確定參數(shù)的類型。如果參數(shù)是一個JavaBean或者一個數(shù)組,那么,程序必須設(shè)置一個定制的SOAP映射注冊項,并通過setSOAPMappingRegistry()方法對Call對象作相應(yīng)的設(shè)置(參見第二篇文章)。SOAP代理假定,當(dāng)出現(xiàn)JavaBean時,SOAP服務(wù)用到的所有JavaBean按照如下方式映射:NameSpace URI設(shè)置成對象ID,Local Part設(shè)置成JavaBean完整的類名。我們部署HelloWorld服務(wù)時正是按照這個要求進(jìn)行,所以一切都不存在問題。

    invoke()方法的剩余部分相當(dāng)簡單:設(shè)置Call對象參數(shù),設(shè)置定制SOAP映射注冊項(如果有必要的話),發(fā)出調(diào)用,接收方法調(diào)用的返回值。如下所示:

    if( params.size() != 0 )
    call.setParams(params);
    if( smr != null )
    call.setSOAPMappingRegistry(smr);
    // 發(fā)出調(diào)用
    Response resp = call.invoke(serverURL, "");
    if( !resp.generatedFault() )
    {
    Parameter ret = resp.getReturnValue();
    return(ret.getValue());
    }
    else
    {
    Fault fault = resp.getFault();
    throw new
    SOAPException(fault.getFaultCode(),fault.getFaultString());
    }


    二、HelloWorld服務(wù)
    下面是HelloWorld服務(wù)的完整代碼。有似曾相識的感覺嗎?

    package hello;
    public class HelloServer
    {
    public String sayHelloTo(String name)
    {
    System.out.println("sayHelloTo(String name)");
    return "Hello " + name + ", How are you doing?";
    }
    public String sayHelloTo(Name theName)
    {
    System.out.println("sayHelloTo(Name theName)");
    return "Hello " + theName.getName() + ", How are you doing?";
    }
    }


    回憶一下,Name是一個簡單的JavaBean,代碼如下:

    package hello;

    public class Name
    {
    private String name;
    public String getName()
    {
    return name;
    }
    public void setName(String name)
    {
    this.name = name;
    }
    }


    事實(shí)上,這里服務(wù)的代碼與第二篇文章中的服務(wù)程序代碼完全一樣。對于服務(wù)開發(fā)者來說,唯一增加的工作是創(chuàng)建Java接口。部署服務(wù)的方法也和第二篇文章中討論的完全一樣,所以這里我不再介紹。相同的地方還不止如此,編譯和運(yùn)行客戶程序的方法也和第二篇文章介紹的一樣。為什么有這么多相同之處呢?因為我們創(chuàng)建的代理是一個非插入式的框架,它不會修改和干涉任何Apache SOAP部件的內(nèi)部工作——無論是客戶端還是服務(wù)端。

    三、其他說明
    本文討論的SOAP代理(可以從文章后面下載)支持以下參數(shù)類型:

    ⑴ 下面的Java基本數(shù)據(jù)類型及其對應(yīng)的對象形式。

    boolean, Boolean,
    double, Double,
    float, Float,
    long, Long,
    int, Integer,
    short, Short,
    byte, Byte


    注:服務(wù)器端總是接收基本數(shù)據(jù)類型。

    ⑵ 任何JavaBean

    注:

  • 該JavaBean不能包含其他JavaBean。
  • 如果數(shù)組或向量包含除字符串或1列出數(shù)據(jù)類型之外的類型,則JavaBean不能包含這類數(shù)組或向量。
      ⑶ 下面的類:String, Vector

      注:

    • Vector可以包含1、2列出的所有類型和字符串。
    • 服務(wù)器端把Vector作為一個對象的數(shù)組接收。
        ⑷ 數(shù)組。數(shù)組元素可以是在1、2中列出的所有類型和字符串(上面已注明的除外)。

        ■ 結(jié)束語
        在這個四篇文章構(gòu)成的系列中,我不僅介紹了SOAP的基礎(chǔ)知識,而且介紹了SOAP 1.1標(biāo)準(zhǔn)的一個優(yōu)秀的實(shí)現(xiàn):Apache SOAP。在本文中,我提供了一個以動態(tài)代理類為基礎(chǔ)的框架,這個框架極大地簡化了使用Apache SOAP的客戶程序開發(fā)者的工作。

        我深切地感到SOAP有著美好的前景,至少有兩個理由使我這么認(rèn)為:首先,SOAP以一些開放的標(biāo)準(zhǔn)為基礎(chǔ),比如XML。這使得無論是Microsoft,還是反Microsoft的企業(yè),都廣泛地接受了SOAP。對于開發(fā)者來說,這無疑是一個天大的好消息。第二,SOAP正在成為其他許多標(biāo)準(zhǔn)的基礎(chǔ),比如UDDI(Universal Description,Discovery,and Integration)。許多人認(rèn)為,Web服務(wù)代表著下一代的Web應(yīng)用開發(fā),而SOAP和UDDI都是Web服務(wù)的關(guān)鍵組成部分。

        ■ 參考資源
      • 下載本文的完整代碼:JavaAndSOAP4_code.zip
      • W3C的SOAP 1.1規(guī)范:
      • http://www.w3.org/TR/SOAP/
      • 有關(guān)動態(tài)代理類的更多信息:
      • http://java.sun.com/j2se/1.3/docs/guide/reflection/proxy.html
      • 關(guān)于IBM SOAP工程的更多信息:
      • http://www.alphaworks.ibm.com/tech/soap4j
      • 下載Apache SOAP:
      • http://xml.apache.org/dist/soap/
      • posted on 2007-11-09 22:07 禮物 閱讀(249) 評論(0)  編輯  收藏 所屬分類: soap
        主站蜘蛛池模板: 18禁美女黄网站色大片免费观看 | 中国人xxxxx69免费视频| 久久亚洲精品无码gv| 国产午夜亚洲精品理论片不卡 | 亚洲&#228;v永久无码精品天堂久久 | 在线视频观看免费视频18| 九九九精品视频免费| 亚洲午夜电影一区二区三区| 日本免费一区尤物| 久久精品一区二区免费看| 亚洲а∨精品天堂在线| 亚洲理论在线观看| 亚洲国产综合精品一区在线播放| 亚洲av无码片vr一区二区三区| 毛片免费观看视频| 嫩草在线视频www免费看| 亚洲国产午夜精品理论片在线播放 | 巨胸喷奶水www永久免费| 亚洲人成图片网站| 亚洲日韩精品一区二区三区| 国产精品免费看香蕉| 国产成人精品免费视频动漫 | 2022中文字字幕久亚洲| 日本一区免费电影| 国产一区二区三区在线免费观看 | 成人久久久观看免费毛片| 亚洲免费视频网址| 亚洲人成人伊人成综合网无码| 亚洲男人在线无码视频| AV在线亚洲男人的天堂| 亚洲大片在线观看| 亚洲国产精品无码久久久秋霞2| 国产无人区码卡二卡三卡免费| 激情小说亚洲色图| 亚洲人精品亚洲人成在线| 亚洲国产精品久久久久秋霞小| 亚洲国产av一区二区三区丶| 亚洲国产AV无码一区二区三区| 亚洲冬月枫中文字幕在线看| 久久精品国产亚洲av瑜伽| 成人电影在线免费观看|