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

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

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

    放翁(文初)的一畝三分地

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      210 隨筆 :: 1 文章 :: 320 評論 :: 0 Trackbacks
     

    三.平臺跨的不容易

           本來這部分內容應該作為很后面的內容,但是由于工作已經作了,也總結了,那么就先寫下來貼一下,也算是個分享吧,這部分內容在網上找了很久都沒有,所以也算是不錯的一個實踐。

           ISV有幾家接了上來,有用PHP的,有.net的,這時候ASF框架的WebService繼功能測試,性能測試,安全性測試進入了一個新的測試階段,兼容性測試。由于ISV的技術力量參差不齊,所以我們需要包辦實現所有語言的客戶端調用Demo的工作,因此對我這個做ASF的人來說,又要懂得各個語言的客戶端調用以及配置,幸好還有一個ISV Support部門也做一些這樣的工作,但是由于都是新手,也沒有太多的指望。

           WebService之所以能夠被認為是SOA最行之有效的技術手段,主要還是因為其通過wsdl規范以xml作為數據和操作請求描述的載體,基于SOAP協議在http或者smtp上傳輸,實現業務邏輯交互與實現語言及平臺的無關性,達到跨平臺交互的效果。然而作為協議,往往來說是制定了規范性的框架,但是框架內的細節實現,不同的廠商,平臺,開發語言,開源框架都會有不同的實現方式,因此也造成了WebService客戶端解析Soap數據包兼容性的問題。這個問題在普通的接口中不容易出現,只是在調用接口返回數據類型為對象數組的時候出現。

    首先出現在Java平臺的兩個比較通用的開源WebService框架上:axis2,xfire。(cxf暫時還沒有去做測試)?,F象:axis2xfire的兩種客戶端都無法正常解析ASF返回的數組對象。例如返回的是Account對象,Accountid,namevalue三個屬性。模擬返回2Account對象,結果axis2客戶端獲得一個數組,內部有一個Account對象,不過三個屬性都是沒有被初始化。xfire客戶端獲得一個數組,內部有兩個Account對象,同樣屬性都沒有被初始化。跟蹤兩個客戶端源碼并結合返回的Soap消息分析,得到了問題的原因。

           SOAP返回的包體如下:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

       <soapenv:Body>

          <_ns_:getUserAccountArr2Response xmlns:_ns_="http://webservice.asf.xplatform.alisoft.com">

             <return xmlns="http://webservice.asf.xplatform.alisoft.com">

                <Account xmlns=””>

                   <accountId>11</accountId>

                   <isDeleted>false</isDeleted>

                   <accountBalance>100.23</accountBalance>

                </Account>

                <Account xmlns=””>

                   <accountId>111</accountId>

                   <isDeleted>false</isDeleted>

                   <accountBalance>111.23</accountBalance>

                </Account>

             </return>

          </_ns_:getUserAccountArr2Response>

       </soapenv:Body>

    </soapenv:Envelope>

    先來解釋Axis2的問題,Axis2客戶端在解析此包體的時候,首先檢查return標簽,然后根據wsdl中的描述確認內部數組對象類型為Account,然后循環獲取結果集構造對象,但是按照axis2的內部邏輯處理正常的情況,應該沒有Account這層標簽,直接是多個結構體組裝而成,由于多了Account這層外圍標簽,導致解析第一個對象就出現問題,因此,就出現了上面描述的結果。此時有些懷疑是否是ASF框架在返回SOAP的時候沒有遵循WSDL的規范,但是沒有檢驗過xfire也不能確定是否是沒有符合規范而造成的。

    在來解釋一下XFire客戶端調用問題的原因。同樣跟蹤了XFire的客戶端代碼,發現問題主要是出在最后給對象獲取屬性值的操作上。首先XFire客戶端啟動時會根據本地的接口包或者對象包路徑來反轉成為namingspace然后和屬性名稱一起生成QName緩存在本地,作為屬性對象。然后當獲得了返回SOAP消息包體的時候,根據這些QName去獲取屬性的內容,但是可以從上面描述的SOAP返回的內容來看,Accountnamingspace丟失了,導致后面各個屬性的namingspace也都丟失了??戳艘幌?/span>ASF在返回SOAP的代碼,的卻在構造SOAP返回包的時候無法獲得對象的namingspace,只有它的上級return類型有namingspace,那么如何解決呢,轉念一想,其實這也是一種規范,wsdl的生成工具大部分都遵循這種包反轉作為namingspace的策略,因此在構造返回包體的時候采取了這個策略來填充SOAP包,XFire客戶端正常。(后話,萬一遇到一些和我一樣自己喜歡修改wsdl的人,那么xfire就未必能夠正常解析這類服務了)。從這兒也驗證了ASF對于WSDL的消息包返回規范是正確的,也就也證明了axis2客戶端的一個缺陷,因此在java平臺暫時不建議客戶使用axis2,同時axis2的客戶端友好度遠遠低于xfire,不過axis2的優勢在于配置靈活以及可插入性(這也是ASF為什么集成axis2作為默認的webservice發布框架的原因,后續blog會回顧其他幾個測試的歷程)

    這還是開始,由于都是開源框架,所以調試和檢測相對來說還比較方便。接著測試部就提出在用.net客戶端調用返回對象數組出現問題,問題和XFire最早一樣。當時我就很肯定地就是應該問題出在解析那些屬性上。說實話,第一次接觸.net,什么都不會,裝了個vs 2005就開始搗鼓,不過.net真是傻瓜工具,調用webservice相當簡單,就只需要建立一個web reference,其中web reference就指向一個wsdl地址,那么.net就自動替你動態生成好client了,然后就像普通的對象調用一樣,直接可以操作此服務(不過ASFwebservice的發布和引用也已經做的這么傻瓜了^_^)。簡單是把雙刃劍,容易上手,但是容易養成不求甚解的習慣,工作到現在,要不是開發框架,我根本不會去管wsdl中哪個元素是什么用處,工具生成好了,用就罷了,只要不出錯。懶倒還是一方面,最痛苦的莫過于沒有辦法看到源碼,只能黑盒測試以及猜測,這時候我覺得java真是好。還問了一個以前的高手朋友,他做了6,7年的java然后轉到.net上,我說怎么跟蹤.net的源碼,他和我說:“據說.net快要開放源碼了”。#_#|| 我回了一句:“我基本上等不到那天了。”言歸正傳,下面是如何分析.net問題的報告。

    Java&.Net WebService兼容問題

    Java發布的webservice .net客戶端調用的時,數組對象類型返回兼容問題。

    問題描述:

    Java發布的WebServiceJava客戶端調用下都是正常的,但是在.net的客戶端調用下,如果返回的類型是數組對象類型,那么就會發現得到了數組,并且數組內部對象生成,但是對象內部的屬性值無法獲得。

    問題分析:

    wsdl中定義數組對象類型返回有兩種方式:

    1    <xs:complexType name="Account">

            <xs:sequence>

                <xs:element minOccurs="0" name="accountBalance" type="xs:double"/>

                <xs:element minOccurs="0" name="accountId" nillable="true" type="xs:string"/>

                <xs:element minOccurs="0" name="isDeleted" nillable="true" type="xs:string"/>

            </xs:sequence>

    </xs:complexType>

        <xs:element name="getUserAccountArrResponse">

            <xs:complexType>

                <xs:sequence>

                    <xs:element maxOccurs="unbounded" minOccurs="0" name="return" nillable="true" type="xsd:Account"/>

                </xs:sequence>

            </xs:complexType>

        </xs:element>

    2    <xs:element name="getUserAccountArr2Response">

            <xs:complexType>

                <xs:sequence>

                    <xs:element minOccurs="0" name="return" nillable="true" type="xsd:ArrayOfAccount"/>

                </xs:sequence>

            </xs:complexType>

        </xs:element>

        <xs:complexType name="Account">

            <xs:sequence>

                <xs:element minOccurs="0" name="accountBalance" type="xs:double"/>

                <xs:element minOccurs="0" name="accountId" nillable="true" type="xs:string"/>

                <xs:element minOccurs="0" name="isDeleted" nillable="true" type="xs:string"/>

            </xs:sequence>

        </xs:complexType>

                <xs:complexType name="ArrayOfAccount">

                    <xs:complexContent>

                        <xs:restriction base="soapenc:Array">

                            <xs:attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:Account[]"></xs:attribute>

                        </xs:restriction>

                    </xs:complexContent>

                </xs:complexType>   

    配置一的情況:

    有兩種場景出現:

    場景一:

    public interface IAccountService2

    {

           public Account checkUserAccount(String accountId);

           public Account[] getUserAccountList(String accountIdBeg,String accountIdEnd);

           public Account[] getUserAccountArr(String accountIdBeg);

           public Account[] getUserAccountArr2(String accountIdBeg);

           public double payForAppOrder(Account account,double fee);

           public void delAccount(Account account,String name);

           public int checkUser(String accountId,String accountId1);

    }

    其中接口中所有的返回或者參數對象都和接口定義在同一個包體內,這樣生成wsdl的時候xsdschema就只有一份,那么.net的客戶端數組對象返回問題不存在。

    場景二:

    public interface IAccountService

    {

           public AccountBean checkUserAccount(String accountId) throws InvocationTargetException;

           public AccountBean[] getUserAccountList(String accountIdBeg,String accountIdEnd);

           public AccountBean[] getUserAccountArr(String accountIdBeg);

           public Account[] getUserAccountArr2(String accountIdBeg);

           public double payForAppOrder(AccountBean account,double fee);

           public void delAccount(AccountBean account,String name);

           public int checkUser(String accountId,String accountId1);

    }

    接口中的返回對象和接口不在一個包內,那么生成的xsdschema就有多個,那么.net的客戶端調用java發布的webservice就存在前面描述的問題。

    因此用同樣的wsdl分別用.netjava發布,通過.net客戶端去調用,前者不存在問題,后者有問題,截獲soap相應報文如下:

    java 返回的soap包:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

       <soapenv:Body>

          <_ns_:getUserAccountArr2Response xmlns:_ns_="http://webservice.asf.xplatform.alisoft.com">

             <return xmlns="http://webservice.asf.xplatform.alisoft.com">

                <Account>

                   <accountId>11</accountId>

                   <isDeleted>false</isDeleted>

                   <accountBalance>100.23</accountBalance>

                </Account>

                <Account>

                   <accountId>111</accountId>

                   <isDeleted>false</isDeleted>

                   <accountBalance>111.23</accountBalance>

                </Account>

             </return>

          </_ns_:getUserAccountArr2Response>

       </soapenv:Body>

    </soapenv:Envelope>

    .net返回的soap包:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

       <soap:Body>

          <getUserAccountArr2Response xmlns="http://webservice.asf.xplatform.alisoft.com">

             <return>

                <accountBalance>12.12</accountBalance>

                <accountId>11</accountId>

                <isDeleted xsi:nil="true"/>

             </return>

             <return>

                <accountBalance>12.12</accountBalance>

                <accountId>11</accountId>

                <isDeleted xsi:nil="true"/>

             </return>

          </getUserAccountArr2Response>

       </soap:Body>

    </soap:Envelope>

    但就作為wsdl中定義的話,return只有一個內容就是Account數組,java的定義應該比較符合定義內容。

    部分結論:

    也就是說在第一種配置情況下,wsdl中包含一個xsdschema,.net客戶端不存在任何問題。wsdl中存在多個schema的情況下,數組對象無法構造成功,但是對于單個對象返回可以正常解析

    解決方案:

    1.修改服務框架服務端代碼適應.net客戶端(不可行,會導致java的出現問題)

    2.將這種特殊接口的schema中定義的類都放在一個包里(覺得不是很合適)

    3.把對象都序列化然后作為結果返回,個人感覺性能比較低,不過可以真的減小跨平臺的問題。

    配置二的情況:

           不存在客戶端調用的構造問題,不過需要改造客戶端代碼(其實就是獲得了xml的數據片斷,自己去解析xml的數據來構造客戶端對象)。此類方法在網上也很通用,可以參看www.salesforce.com提供給第三方的API接口介紹,就是類似的。

    C# Example

    private void querySample() 

    {

     QueryResult qr = null;

     binding.QueryOptionsValue = new sforce.QueryOptions();

     binding.QueryOptionsValue.batchSize = 250;

     binding.QueryOptionsValue.batchSizeSpecified = true;

     qr = binding.query("select FirstName, LastName from Contact");

     bool bContinue = true;

     int loopCounter = 0;

     while (bContinue) 

     {

        Console.WriteLine(""nResults Set " + Convert.ToString(loopCounter++) + " - ");

        //process the query results

        for (int i=0;i<qr.records.Length;i++)

        {

        sforce.sObject con = qr.records[i];

        string fName = con.Any[0].InnerText;

        string lName = con.Any[1].InnerText;

        if (fName == null)

          Console.WriteLine("Contact " + (i + 1) + ": " + lName);

        else

          Console.WriteLine("Contact " + (i + 1) + ": " + fName + " " + lName);

        }

        //handle the loop + 1 problem by checking to see if the most recent queryResult

        if (qr.done) 

          bContinue = false;

        else

          qr = binding.queryMore(qr.queryLocator);

        }

        Console.WriteLine(""nQuery succesfully executed.");

        Console.Write(""nHit return to continue...");

        Console.ReadLine();

     } 

    }

    此時,我們的客戶端代碼修改成為:

    原來的代碼:

    jdk2Service.AccountService service5 = new jdk2Service.AccountService();

    jdk2Service.Account[] re = service5.getUserAccountArr("demo");

    jdk2Service.Account re2 = service5.checkUserAccount("test");

    現在的代碼:

    jdkService.AccountService service3 = new jdkService.AccountService();

    jdkService.ArrayOfAccountBean res = service3.getUserAccountArr("tea");

    string name = res.Any[0].FirstChild.InnerText;//獲取了第一個返回對象的第一個屬性值。

    這種模式比較通用在現在的跨平臺的客戶端調用webservice。

    因此考慮AEP接口改造成為這種方式,同時可以給客戶封裝類似的構造函數庫提供給客戶使用。

    結束語:

           這個報告發給了我們的架構師們以及相關人員,晚上下班到家,收到了老大的郵件,讓我們總架構師向微軟提出這個問題,看是否真的是這樣的情況,能否有好的方法解決。這讓我想起了前一陣子誰說的一句話:“有多少人打過微軟的客戶服務電話反映過情況”。赫赫,我們這就算是反映了,效果么……,覺得求人不如求己,開源好啊^_^

    更多的內容請訪問我的bloghttp://blog.csdn.net/cenwenchu79

    posted on 2007-11-21 22:16 岑文初 閱讀(1719) 評論(2)  編輯  收藏

    評論

    # re: 在路上---基于SCA規范的應用服務框架成長記(三)(連載中...) 2008-05-06 17:26 hi
    請教關于tuscany中spring實現component的問題,
    我現在遇到的問題是:我們的系統中關于連接池,事務管理器的spring配置文件是由核心模塊提供的,業務模塊可以直接引用核心模塊提供的bean。這樣就造成了spring的application context分布在多個配置文件中,而tuscany只能指向一個單獨的spring配置文件來構造application的context,不知道您是如何解決這個問題的,謝謝!  回復  更多評論
      

    # re: 在路上---基于SCA規范的應用服務框架成長記(三)(連載中...) 2008-05-06 17:44 岑文初
    改造Spring的組件,支持import  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 成人免费视频国产| 色www永久免费视频| 亚洲综合av永久无码精品一区二区| 亚洲丁香婷婷综合久久| 最近最好的中文字幕2019免费| 亚洲欧洲另类春色校园网站| 美女被cao免费看在线看网站| 亚洲国产综合第一精品小说| 日本一区二区三区免费高清| 亚洲sss综合天堂久久久| 最近中文字幕mv免费高清视频7| 亚洲一区二区三区丝袜| 日本成人免费在线| 国产日韩精品无码区免费专区国产| 国内精品99亚洲免费高清| 国产在线精品一区免费香蕉| 18亚洲男同志videos网站| 免费H网站在线观看的| 亚洲精品无码aⅴ中文字幕蜜桃| 免费国产在线观看| 免费无码又爽又刺激网站直播| 亚洲国产精品久久久久网站| 国产精品69白浆在线观看免费| 亚洲6080yy久久无码产自国产| 2022中文字字幕久亚洲| 香港a毛片免费观看| 亚洲激情视频图片| 亚洲精品无码av天堂| 久久久久久影院久久久久免费精品国产小说 | 亚洲视频精品在线观看| 亚洲第一成年免费网站| 免费人成网站永久| 亚洲视频在线视频| 日韩在线a视频免费播放| 国产在线精品一区免费香蕉 | 日本亚洲视频在线| 在线精品免费视频无码的| 国产在线观a免费观看| 亚洲人妖女同在线播放| 亚洲精品麻豆av| 中文字幕无码成人免费视频|