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

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

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

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

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

           上周周四快速了結(jié)了對于搜索引擎的集成以后,又從新回到對ISV WebService接口集成和測試的支持中。測試部發(fā)現(xiàn)了一個很棘手的問題,將WS-Security集成到了ASF(應(yīng)用服務(wù)框架)中以后,接口中如果出現(xiàn)中文,就會導(dǎo)致異常拋出。這個問題相關(guān)的同事已經(jīng)跟蹤了1,2天了,但是還是沒有頭緒,離周末還有一天,我趕緊接手,希望能夠趕在測試部下周整體測試前修復(fù)這個問題。其實前面做了那么多工作,如果一旦這個問題被卡住,那么就會前功盡棄了。

           首先工作就是要確定,究竟是加了WS-Security導(dǎo)致中文問題,還是本來WS的中文返回就有問題。簡單的做了單元測試驗證了一下,確認了的卻是增加了WS-Security導(dǎo)致的中文作為參數(shù)或者作為返回值都回拋出異常。根據(jù)異常的翻譯來看,就是因為在消息體中出現(xiàn)了非法字符。前幾天一位同事讓我?guī)兔?/span>WS的一個中文問題時發(fā)現(xiàn),在Http頭上對方返回的編碼方式是utf-8而在SOAP消息體中,XML的編碼方式卻寫著gbk,所以客戶端解析器在解析SOAP消息中的xml時候采用的是Utf-8的編碼方式,解析出來的中文自然是不對的。同時翻閱了一下資料,在xml  1.0的內(nèi)部二進制嵌入必須用base64編碼一下,否則是不允許出現(xiàn)非法字符,在xml 1.1已經(jīng)對這部分作了擴展。所以這次集成了WS-Security產(chǎn)生的問題,可能就會因為這兩種原因造成的。

           但是事實上并不是這兩方面的原因造成,Axis2和當(dāng)前很多Web Service框架都采用了Stax方式的Jaxp(Java API for xml processing),在帶WS-Security和不帶的兩種流程中,所用的Jaxp的讀寫解析器采用的是不同的解析器,所以才會出現(xiàn)了上面的問題,因此還是要從根本上去了解Stax模式的Jaxp框架結(jié)構(gòu)及工作模式。

    Stax(Streaming API for XML)

    背景

    Stax不是很新的概念了,在2002年就被提出,在2004年被JCP作為編號為173JSR正式發(fā)布。因此在我們?nèi)粘i_發(fā)中如果說到Jsr 173就是關(guān)于Streaming API for XML的內(nèi)容,同時,在lib中如果列了jsr-173.jar或者stax-api.jar也就是對于Streaming API for XML的接口定義包,同時這個包內(nèi)只是定義框架接口,并沒有具體的實現(xiàn),JSR 173是接口定義規(guī)范,各個開源組織或者廠商都可以根據(jù)規(guī)范實現(xiàn)自身的Stax,這個后面的結(jié)構(gòu)介紹中就會提到。Stax的創(chuàng)始者是BEA的兩位系統(tǒng)工程師,所以在我們?nèi)蘸蟮某鲥e中,如果類似于com.bea.xml.stream.XXX  Class not found 等錯誤,多半是在所有的lib庫中沒有對應(yīng)的Stax的具體實現(xiàn),只有接口定義。當(dāng)前支持JSR的實現(xiàn)有Sun,Bea,Oracle,Breeze Factor和其他的一些開源項目(最出名的就是codehauswoodstox)。

    Jdk 1.6種已經(jīng)把Stax集成到了內(nèi)部(javax.xml.transform.stax),順便說一句的就是,在jdk1.5中,范型和對于Collection的增強是很成功的,而在jdk1.6中雖然沒有1.5的很多新特性的融入,但是仔細觀察一下就可以發(fā)現(xiàn),其實對于xmlweb service的處理和支持作了不少的增強,其實也是針對當(dāng)前SOA的大趨勢作的技術(shù)方面的增強,很多概念和實現(xiàn)其實很早就在我們的應(yīng)用開發(fā)中得到體現(xiàn),個人覺得這也是Sun在開源后的最大受益之處(利用開源來匯集更多的亮點和精華),包括對于1.7OSGI的暢想,其實都是大勢所趨。這讓我想起了昨天看程序員增刊第一部分對于Web2.0中的特質(zhì)的一項描述,利用集體智慧,有所放棄有所收獲,放棄了獨享的知識專利(當(dāng)然核心部分可以保留),獲得的是廣泛的集體參與所帶來的智慧亮點。

    Stax結(jié)構(gòu)體系和功能描述

    Stax的提出開始,其本身就只是一個框架性的規(guī)范,并沒有具體的實現(xiàn)約束,這也為各個開發(fā)商和開源組織認可這個規(guī)范提供了一個最基本的優(yōu)勢條件。這點也是當(dāng)前所有的有生命力的框架或者系統(tǒng)所具備的最基本的特點之一,開放性,制定接口,規(guī)范流程,但是不約束具體的實現(xiàn)。

    功能描述:

           這是我第一次去看JSR的描述,JSRJava Specification Request的縮寫,也就是規(guī)范申請,其中所需要填的描述中就詳細的寫出了申請為JSR的目的(這比類似于國內(nèi)申請專利之類的,不過感覺更為簡潔和開放)。

           Streaming API for XML 描述的是一種基于javapull方式來處理XMLAPI。Streaming API通過暴露簡單的Iterator模式API提供給開發(fā)者處理XML的控制權(quán)。同時當(dāng)前兩種關(guān)于XML的規(guī)范,JAXBJAX-RPC也十分需要通過Stax模式來處理xml。

           其實早在Stax出現(xiàn)之前,jdk中的已經(jīng)有了jaxp家族,saxdom,這兩種API分別針對不同的應(yīng)用場景作了很好的封裝。SAX是用于處理XML的事件驅(qū)動方法,由很多的回調(diào)函數(shù)組成。而DOM則是將XML解析成為內(nèi)存中的樹狀結(jié)構(gòu),然后通過API來對XML中的元素和標(biāo)簽進行分析。SAX速度快,需要的內(nèi)存小,但是無法修改XML,而DOM可以提供對于XML任意節(jié)點的訪問,同時也可以寫入內(nèi)容到XML,但是缺陷就是速度慢,消耗內(nèi)存大,需要把XML全部解析完以后才能夠繼續(xù)操作。

           網(wǎng)上對于Stax的好處有很多很詳細的文檔,就我自己的學(xué)習(xí)理解來看,比較重要的幾點就是:1.pull方式替代了push。Stax從名字上就可以看出和SAX十分相像,其實很大的一點不同就是在于Pull替代了Push。Sax可以實現(xiàn)很多固定的回調(diào)函數(shù),然后在執(zhí)行XML解析的過程中不斷的被調(diào)用和處理,但是缺點很明顯,首先被動回調(diào)導(dǎo)致開發(fā)者無法根據(jù)場景來動態(tài)選擇如何裁減事件處理需求,同時無法同時處理多個XML。2.StaxSAX可以更靈活定制事件處理條件。3.Stax可以寫入XML4.Stax除了和SAX提供了一樣的API模式的處理方式,還封裝了Event模式的對象處理方式。5.StaxDOM性能高,應(yīng)用場景廣泛,特別是當(dāng)前很多應(yīng)用處理xml數(shù)據(jù)流時都需要邊讀邊分析,當(dāng)流結(jié)束以后就自動關(guān)閉了,此時可能已經(jīng)將流釋放,然而此時在作DOM分析已經(jīng)無法實現(xiàn),而Stax正好滿足了這種需求。因此對于Stax適用范圍的描述如下:需要清晰,有效的pull-parsing模式分析XML,另一方面也需要靈活的對XML Stream進行讀寫操作,需要創(chuàng)建新的事件類型和擴展XML的文檔類型以及屬性的情況。

    Stax體系結(jié)構(gòu):

           下圖中是Stax接口部分的類圖,基本上已經(jīng)包括了Stax規(guī)范中的大部分接口定義。


    Stax接口類圖

     

     

    兩類API設(shè)計接口:Cursor API,Iterator API

           Cursor API的兩個接口定義為:XMLStreamReaderXMLStreamWriter。這部分接口提供了類似于游標(biāo)方式的方法定義,能夠在XML解析過程中,從XML文檔流獲取或者寫入信息,同樣也類似于游標(biāo)讀取信息一樣,只能前進不能后退,在任意一個時刻能夠返回XML中的部分信息片斷。

           Iterator API的兩個接口定義為:XMLEventReaderXMLEventWriterIterator APIXML輸入流看作了一組離散的事件對象,這些XML流讀入并被Parser分析,然后被解析成為這類事件對象,在開發(fā)者的應(yīng)用程序中,可以主動的Pull(拉)出需要處理的事件對象。

    對于這兩種API的選擇基于下面幾點:

    1.內(nèi)存有限類似于J2ME可以選擇使用cursor API

    2.性能是第一優(yōu)先級,創(chuàng)建底層的庫或者框架結(jié)構(gòu)時使用cursor API更有效。

    3.如果需要類似于管道處理XML,使用Iterator API

    4.如果想要修改事件流,使用Iterator API。

    5.如果需要應(yīng)用能夠處理可插入的處理流程,使用Iterator API

    6.總的來說,如果你對性能要求不是很高,建議使用Iterator API,因為它更靈活和易擴展。

    工廠類

    Stax采用的是抽象工廠模式來動態(tài)的根據(jù)環(huán)境配置加載不同的Stax的實現(xiàn)。在我原先查找問題的時候看來也是產(chǎn)生WS-Security中文問題的根源,當(dāng)帶WS-Security的時候?qū)τ?/span>XML流分析和讀寫采用了codehauswoodstox包中針對StaxCursor API實現(xiàn),而不帶WS-Security時對于XML流分析和讀寫采用的是axis2中實現(xiàn)的Cursor API。 

    工廠類都是抽象類,因此都需要實例來繼承實現(xiàn),如何選取工廠類的實現(xiàn),并且通過工廠類來生成兩套API的實現(xiàn),按照以下的規(guī)則來載入:(以XMLInputFactory為例)

    1.       讀取系統(tǒng)屬性,看配置中是否有javax.xml.Stream.XMLInputFactory等配置的描述。

    2.       讀取Jrelib/xml.stream.properties文件來讀取配置。

    3.       從可讀取的Jar中讀取在META-INF/services/javax.xml.stream.XMLInputFactory文件來判斷載入哪一個的工廠類實現(xiàn)。

    4.       使用默認的XMLInputFactory實例。

    其他接口的說明

           XMLResolver接口可以在分析XML的過程中對于某些資源解析定位到定義和實現(xiàn)的方法上。

           XMLReporter接口用于報告所有的非致命的錯誤,致命錯誤通過XMLStreamException來報告。

    對于接口使用細節(jié)可以參看sun公司的webservice tutorial。


    WS-Security中文問題解決

           在對新一代的Jaxp做了基本學(xué)習(xí)以后,那么對于axis2如何處理SOAP消息有了基本的了解,在跟蹤了代碼調(diào)試以后,發(fā)現(xiàn)問題主要是出在axis2rampart模塊的Axis2Util類,其中的兩個方法getDocumentFromSOAPEnvelope(SOAPEnvelope env, boolean useDoom)getSOAPEnvelopeFromDOMDocument(SOAPEnvelope env, boolean useDoom)。在有WS-Security和沒有的不同情況下,傳入的參數(shù)useDoomtruefalse,導(dǎo)致走了兩個不同的解析流程。當(dāng)useDoomtrue的時候,axis2通過SOAPEnvelope對象和axis2Streaming parser來解析和構(gòu)建Dom Document。當(dāng)useDoomfalse的時候,首先將SOAPEnvelope對象讀入字節(jié)數(shù)組流,然后在根據(jù)Stax工廠生成實例,并且構(gòu)造出StAXSOAPModelBuilder,然后返回通過StAXSOAPModelBuilder獲得的Dom Document對象。

           察看了一下調(diào)用者傳入?yún)?shù)的地方,其實是通過MsgContext的參數(shù)配置來確定采取什么策略,因此只需要將axis2.xml中配置增加一個parameter,設(shè)置useDoomtrue即可?;蛘呔褪亲鲆粋€handle或者phaseInflowoutflow中配置這個參數(shù)即可。

           搞了那么久也就是修改一個配置,如果光從結(jié)果看,花了兩天時間真是比較浪費,但是如果從過程來看,那么這兩天時間所學(xué)到的那還是比較值的。

           由于第二天是周日,問題解決了也就沒有再繼續(xù)細究。但是周日早晨晨跑的時候,給自己列了三個疑問,首先為什么走系統(tǒng)獲取的Stax會有問題,再則如果我用sunjaxp實現(xiàn)來替換是否能夠解決此問題而不需要配置useDoom。useDoom兩種處理模式究竟有什么區(qū)別。

    問題的再次細究

           周一上班的時候還是記得周日早晨提出的三個問題,因此就仔細的再分析了一下這三個問題。

    首先是采取sunjaxp替換,這個實現(xiàn)在sunjwsdp中已經(jīng)包含了,替換以后然后強制在jre的配置文件中指定使用,出現(xiàn)了異常,看來直接使用還不行,需要針對一些參數(shù)作配置,特別是對namingspace的解析,同時也沒有花更多時間去細研究。

    再則,仔細回想了一下我在定位這個問題的時候做的實驗,我曾經(jīng)試圖將中文先用Base64編碼,然后服務(wù)端接收到以后回傳,客戶端再用Base64解碼,沒有任何問題。有時候換一個中文或者中文前后有字母數(shù)字,也可以正常處理,同時在跟蹤代碼過程中看過SOAP消息中的內(nèi)容,內(nèi)容是亂碼。這讓我有點啟發(fā),例如我輸入?yún)?shù)為“岑文初”每次始終都會出錯,如果輸入為“岑文”,就沒有問題,看了看內(nèi)存內(nèi)的變量,發(fā)現(xiàn),原來如果是“岑文初”的時候SOAP消息中的標(biāo)簽封閉被破壞,如果是“岑文”,雖然是亂碼,但是沒有破壞標(biāo)簽的封閉。

    仔細看了看上次提到的兩個流程,其實兩個流程除了parser不同以外,對于SOAPEnvelope的處理也是不一樣的,走UseDoom的是直接將分析好的Dom對象返回,不做附加的處理,只是根據(jù)Envelope生成了SOAP的解析器以及配置了StaxCursor的兩個接口實現(xiàn)類。不走UseDoom的情況則是完全將SOAPEnvelope再次序列化并且通過外部的Stax實現(xiàn)來解析和處理,但是問題就出在對象到字節(jié)流的序列化過程,默認的是使用了SOAP規(guī)定的utf-8編碼方式,因此在這個過程中有些中文的內(nèi)容就破壞了SOAP的消息包XML的標(biāo)簽合法性,導(dǎo)致外部解析器分析出現(xiàn)問題。如果將傳入和傳出的中文都編碼成utf-8沒有任何問題。

    問題總結(jié)就是其實根源在于對于內(nèi)容中的中文字符編碼時采用Utf-8破壞了xml的封閉性,而我開始采用的useDoom正好規(guī)避了這個過程,也就自然通過了。但是就其設(shè)計本身來說,rampart應(yīng)該是贊同使用useDoomfalse的方式,這才是真正的Stax的模式,同時有很好擴展性。另一方面?zhèn)€人覺得類似于這種抽象工廠機制來說,最好不要在系統(tǒng)變量或者jre中強制指定,這樣會導(dǎo)致一些意想不到的問題,雖然是規(guī)范,但是細節(jié)實現(xiàn)畢竟有差異,因此一些特殊的開源框架的一些莫名其妙的xml解析問題也常常由于這些引起。

    幾點感悟

           靈活的SPIService Provider Interface)模式是當(dāng)前框架設(shè)計以及底層設(shè)計的必要特質(zhì),開放才會發(fā)展得更好。

           靈活是把雙刃劍,在遇到一些靈活的框架設(shè)計時,首先必須了解其原理和結(jié)構(gòu),然后根據(jù)實踐來驗證問題的緣由。

           抽象工廠還是有適用場景的,類似于JaxpSCA等框架的實現(xiàn),抽象工廠以及利用JarMETA-INF/services來載入SPI的實現(xiàn)是IOC的一種很好的補充。


         更多內(nèi)容請訪問我的blog:http://blog.csdn.net/cenwenchu79

    posted on 2007-12-04 16:10 岑文初 閱讀(1363) 評論(3)  編輯  收藏

    評論

    # re: WS-Security 中文問題&Stax(Streaming API for XML ) 2007-12-05 08:47 vagrant
    lz的文章一路看過來,對我來說深也很精辟,很喜歡.....今天忽然有個疑問,想問問lz,你和《貞觀長歌》里的"岑文本"有關(guān)系么~_~.  回復(fù)  更多評論
      

    # re: WS-Security 中文問題&Stax(Streaming API for XML ) 2007-12-05 09:20 岑文初
    @vagrant
    先謝謝你的支持啦:),不過我是沒看過你說的那電視,至于我的名字,呵呵,我爺爺取的,應(yīng)該沒什么太大關(guān)系。
      回復(fù)  更多評論
      

    # re: WS-Security 中文問題&Stax(Streaming API for XML )[未登錄] 2008-05-23 13:59 Terry
    請問是直接加上這么一句嗎?
    <parameter name="useDoom">true</parameter>
    我加上了好上沒有作用啊,返回的還是亂碼誒;
    還是您說“或者就是做一個handle或者phase在Inflow和outflow中配置這個參數(shù)即可。”請問能否具體說下如何實現(xiàn)呢,謝謝  回復(fù)  更多評論
      


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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产91久久久久久久免费| 国产亚洲精品va在线| 免费人成动漫在线播放r18| 亚洲午夜激情视频| 99热在线观看免费| 亚洲av日韩av永久无码电影| 中文字幕在线亚洲精品| 91精品国产免费久久久久久青草| 亚洲精品第一国产综合亚AV| 亚洲精品无码午夜福利中文字幕 | 免费又黄又爽又猛大片午夜| 亚洲AV无码国产在丝袜线观看| 国产三级在线观看免费| 国产日韩在线视频免费播放| 亚洲美女视频网站| 亚洲乱码中文字幕综合234| 曰批视频免费40分钟试看天天| 美女扒开屁股让男人桶爽免费| 久久精品国产亚洲AV无码娇色| 免费一看一级毛片人| 麻豆视频免费播放| 久久国产美女免费观看精品| 最新亚洲卡一卡二卡三新区 | 亚洲欧美日韩久久精品| 久久青青草原亚洲AV无码麻豆| 女人18特级一级毛片免费视频| 成全在线观看免费观看大全 | 亚洲精品无码久久久久秋霞| 亚洲av伊人久久综合密臀性色| 日本大片在线看黄a∨免费| 热re99久久6国产精品免费| 一级做α爱过程免费视频| 亚洲字幕AV一区二区三区四区| 香蕉视频在线观看亚洲| 亚洲国产天堂久久久久久| 成人片黄网站色大片免费| 亚洲黄色片免费看| 久久九九全国免费| 国产精品免费久久| 看一级毛片免费观看视频| 亚洲国产欧美国产综合一区 |