posts - 431,  comments - 344,  trackbacks - 0

          概覽

          Smooks是一個開源的Java框架,用于處理“數(shù)據(jù)事件流”。它常常被認為是一個轉(zhuǎn)換框架并以此被用于好幾個產(chǎn)品和項目中,包括JBoss ESB(以及其它ESB)。然而究其核心,Smooks未提及“轉(zhuǎn)換”或者其它相關的詞匯。它的應用遠不只這一點!

          Smooks的工作是將結(jié)構(gòu)化/層次化的數(shù)據(jù)流轉(zhuǎn)變成“事件”流,然后交與“訪問者邏輯(Visitor Logic)”進行分析,生成結(jié)果(可選的)。

          源 ->結(jié)構(gòu)化事件流(訪問者邏輯) ->結(jié)果

          那么,有哪些工作是這個工具可以完成,而sax和dom等工具不能完成的呢?鑒于Smooks構(gòu)建于這些技術之上,所以簡單的回答是“沒有”。Smooks真正的價值在于能更方便地消費SAX和DOM(Smooks現(xiàn)在還不支持基于StAX的過濾器)。它提供了一個訪問者API,以及一個配置模型,允許你輕易地將訪問者邏輯的目標設定為具體的SAX事件(如果使用的是SAX過濾器)或DOM元素(如果使用的是DOM過濾器)。Smooks同時還以一種標準方式簡化了對非XML源數(shù)據(jù)格式(EDI,CSV,JSON,Java等等)的消費,即由數(shù)據(jù)源產(chǎn)生的標準事件流變成了所有這些不同源數(shù)據(jù)格式的事實上的規(guī)范形式。這正是Smooks工作的關鍵!

          使用Smooks的方式有兩種,你可以使用其中之一或結(jié)合使用它們:

          • 模式一:你可以完全投入到Smooks中,編寫你自己的定制訪問者邏輯事件處理器,將其用于處理一個數(shù)據(jù)源事件流中特定事件。使用這一模式,你必須熟悉核心的API。
          • 模式二:你可以重用由Smooks發(fā)行版提供的開箱即用解決方案,其數(shù)目正在不斷的增長中。在這種模式下,你只需要重用別人創(chuàng)建的組件即可,重新配置它們來處理你的數(shù)據(jù)源,例如,通過配置一些參數(shù)就可以由EDI數(shù)據(jù)源生成Java對象模型。

          在這篇文章中,我們會快速地瀏覽一遍Smooks v1.1發(fā)行版提供的一些開箱即用的功能,即那些你不需要編寫任何代碼就可加以利用的功能(即模式二)。這包括:

          1. 多源數(shù)據(jù)格式:“輕易”地消費諸多流行的數(shù)據(jù)格式,包括XML,EDI,CSV,JSON和Java(是的,你可以以一種聲明性的方式完成java到java的轉(zhuǎn)換)。
          2. 轉(zhuǎn)換:利用諸多選項消費由數(shù)據(jù)源產(chǎn)生的事件流,產(chǎn)生其它格式的結(jié)果(即,對源進行“轉(zhuǎn)換”)。這包括能在過濾源數(shù)據(jù)流時對Smooks所捕獲的數(shù)據(jù)模型應用FreeMarker和XSL模板。鑒于這些模板資源能被運用于源數(shù)據(jù)事件流內(nèi)部的事件,因此它們能被用來執(zhí)行“基于片斷的轉(zhuǎn)換(fragment based transforms)”。這意味著Smooks能被用于對數(shù)據(jù)源的片斷執(zhí)行轉(zhuǎn)換,而不僅限于將數(shù)據(jù)源作為一個整體來施行轉(zhuǎn)換。
          3. Java綁定:以一種標準方式由所支持的數(shù)據(jù)格式(即不僅限于XML)創(chuàng)建和生成Java對象模型/圖。由EDI數(shù)據(jù)源 生成某對象模型的配置與由XML數(shù)據(jù)源或JSON數(shù)據(jù)源生成對象模型所進行的配置幾乎一模一樣。唯一區(qū)別在于綁定配置的“事件選擇器(event selector)”取值不同。
          4. 大型消息處理:Smooks支持多種處理大型消息(GBs)的方式,它是通過基于SAX的過濾器完成的。由于綜合了 基于片斷轉(zhuǎn)換、Java綁定,以及使用節(jié)點模型混合DOM和SAX模型所帶來的能力,Smooks可以使用較低的內(nèi)存空間處理大型消息。這些能力允許你執(zhí) 行直接的1對1轉(zhuǎn)換,同時也支持對大型消息數(shù)據(jù)流執(zhí)行1對多的分解、轉(zhuǎn)換和路由。
          5. 消息修飾:使用數(shù)據(jù)庫數(shù)據(jù)修飾消息。這可以按片斷來完成,即你可以按片斷來管理在一個片斷上的修飾。與此相關的一個用例是一個包含了消費者ID列表的消息在發(fā)往另一個流程前需要從數(shù)據(jù)庫提取消費者地址和概要數(shù)據(jù)來豐富。
          6. 基于可擴展XSD的配置模型:從Smooks v1.1開始,你可以用自己的可重用定制訪問者邏輯配置模型來擴展Smooks XSD配置名字空間。創(chuàng)建這些定制配置擴展只是一項簡單的配置工作,這個工作極大的增進了這些重用組件的可用性。所有的現(xiàn)有Smooks預置組件都利用了這一工具。

          處理不同數(shù)據(jù)格式

          Smooks的一個關鍵特性就是能很容易地將其配置成用標準方式處理不同數(shù)據(jù)格式。這意味著如果你為Smooks開發(fā)了一些定制的訪問者邏輯,這些代碼可以立即用于處理任何受支持的數(shù)據(jù)格式,就仿佛是Smooks的預置組件(Java綁定等)一樣。與之相關的,如果你為某種非預置支持的數(shù)據(jù)格式(例如 YAML)開發(fā)了一個定制的閱讀器實現(xiàn),你立即就具備了一個能力:使用所有可獲得的預置訪問者邏輯(例如,Java綁定組件)來處理該類型數(shù)據(jù)產(chǎn)生的數(shù)據(jù)事件。使這成為可能的原因在于Smooks組件處理的是標準化的事件流(即規(guī)范形式)。

          Smooks提供對處理XML、EDI、CSV、JSON和Java對象的開箱即用的支持。默認情況下,Smooks將源數(shù)據(jù)流當作XML來讀?。ǔ橇碛信渲茫?。一個例外是Java對象源,它將被自動識別。對于其它所有數(shù)據(jù)格式類型,在Smooks配置里必須配置一個“閱讀器”。下面是一個CSV閱讀器的配置實例:

          <xml version="1.0"?>

          <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"

          xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.1.xsd">



           <csv:reader fields="firstname,lastname,gender,age,country" separator="|" quote="'" skipLines="1"/>



          <smooks-resource-list>

          EDI、JSON等閱讀器的配置方式類似,都是通過唯一的配置名字空間進行的,比如<edi:reader></edi:reader><json:reader></json:reader>等。這些名字空間式的配置通過前面所講到的基于可擴展的XSD配置模型得以實現(xiàn)。

          配置好的閱讀器負責將源數(shù)據(jù)流翻譯成結(jié)構(gòu)化的數(shù)據(jù)事件流(即規(guī)范形式——目前基于SAX2)。Smooks監(jiān)聽這一事件流,在合適的時候觸發(fā)配置好的訪問者邏輯(例如模板或綁定資源)。

          執(zhí)行一個Smooks過濾器流程

          這很簡單:

          private Smooks smooks = new Smooks("/smooks-configs/customer-csv.xml");



          publicvoid transCustomerCSV(Reader csvSourceReader, Writer xmlResultWriter) {

              smooks.filter(new StreamSource(csvSourceReader), new StreamResult(xmlResultWriter));

          }

          Smooks.filter()方法消費標準的javax.xml.transform.Sourcejavax.xml.transform.Result類型。Smooks項目同樣定義了諸多新實現(xiàn)。

          可視化非XML的結(jié)構(gòu)化數(shù)據(jù)事件流

          XML是最簡單的“由源數(shù)據(jù)流產(chǎn)生事件流”的可視化方案。所以對于一個XML源而言,不存在真正的問題。而對非XML源(如CSV),事情就不那么簡單了。該源一般與XML毫無共通之處。為了解決這個問題,Smooks提供了執(zhí)行報告產(chǎn)生器(Execution Report Generator)工具。這一工具的一大用途就是幫助你對非XML數(shù)據(jù)源產(chǎn)生的事件流進行可視化,格式為XML。它同樣是很好的調(diào)試工具。

          這一報告產(chǎn)生工具被注入到了Smooks的執(zhí)行上下文中:

          private Smooks smooks = new Smooks("/smooks-configs/customer-csv.xml");



          publicvoid transCustomerCSV(Reader csvSourceReader, Writer xmlResultWriter) {   

              ExecutionContext executionContext = smooks.createExecutionContext();



              executionContext.setEventListener(new HtmlReportGenerator("target/report/report.html"));

              smooks.filter(new StreamSource(csvSourceReader), new StreamResult(xmlResultWriter), executionContext);

          }

          (在Smooks v1.1中)其輸出是如下的一個HTML頁面:

          JBoss正在為Smooks開發(fā)一個Eclipse編輯器,它將作為JBoss Tools的一部分。這些工具將進一步簡化可視化并操作非XML數(shù)據(jù)源事件流的過程。

          拆分、轉(zhuǎn)換與路由

          這一用例很好地示范了如何組合幾個Smooks功能來執(zhí)行一個更復雜的任務。

          繼續(xù)CSV的例子,我們有以下的基本需求:

          1. CSV流可能會很大,因此我們需要使用SAX過濾器。
          2. 我們需要將每個CSV記錄路由到一個JMS端點,格式是XML。這意味著我們需要拆分,轉(zhuǎn)換和路由這些消息。

          Smooks使用諸如XSL和FreeMarker這樣的流行模板技術來對使用基于片斷的轉(zhuǎn)換提供支持。Smooks同時還提供了從源事件流(同樣可能是非XML的)抓取DOM模型的能力,就算在使用SAX過濾器的情況下也能實現(xiàn)。有了這一功能,Smooks能夠從源數(shù)據(jù)片斷中構(gòu)建“迷你”DOM模型并讓其它Smooks資源(如FreeMarker模板和Groovy腳本資源)可以利用它們。采取這種方式,你能在保持以流式環(huán)境進行處理的同時,得到某些DOM處理模型的好處。對于此處所說的用例,我們將使用FreeMarker作為模板技術。

          Smooks同樣對將數(shù)據(jù)片斷(由源數(shù)據(jù)片斷所產(chǎn)生)路由到多個不同的端點類型(即JMS,文件或數(shù)據(jù)庫)提供了開箱即用的支持。如同Smooks中的所有事物一樣,這種能力總是可以被擴展或被其他用例重復使用,例如,可以輕而易舉的插入一個定制的電子郵件訪問者組件。JBoss ESB(以及其它的ESB)從運行于ESB之上的Smooks過濾流程內(nèi)部提供定制的Smooks訪問者組件來完成基于片斷的ESB端點路由。

          那么配置Smooks來完成上述用例就十分簡單了:

          <xml version="1.0"?>

          <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"

          xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.1.xsd"

          xmlns:jms="http://www.milyn.org/xsd/smooks/jms-routing-1.1.xsd"

          xmlns:ftl="http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd">



          <params>

          (1) <param name="stream.filter.type">SAXparam>

          params>



          (2) <csv:reader fields="firstname,lastname,gender,age,country" separator="|" quote="'" skipLines="1"/>



          (3) <resource-config selector="csv-record">

          <resource>org.milyn.delivery.DomModelCreatorresource>

          resource-config>



          (4) <jms:router routeOnElement="csv-record" beanId="csv_record_as_xml" destination="xmlRecords.JMS.Queue"/>



          (5) <ftl:freemarker applyOnElement="csv-record">

          (5.a) <ftl:template>/templates/csv_record_as_xml.ftlftl:template>

          <ftl:use>

          (5.b) <ftl:bindTo id="csv_record_as_xml"/>

          <ftl:use>

          <ftl:freemarker>



          <smooks-resource-list>

          1. 配置(1)指示Smooks使用SAX過濾器。
          2. 配置(2)指示Smooks對所提供的配置使用CSV閱讀器。
          3. 配置(3)指示Smooks為記錄片斷(參見上述執(zhí)行報告)創(chuàng)建節(jié)點模型。每個記錄的節(jié)點模型都將覆蓋前一個片斷產(chǎn)生的節(jié)點模型,所以任一已知時刻內(nèi)存中都絕不會出現(xiàn)一個以上(作為一個節(jié)點模型)的CSV記錄。
          4. 配置(4)指示Smooks在每個片斷結(jié)束時將beanId“csv_record_as_xml”的內(nèi)容路由到指定的JMS目的地。
          5. 配置(5)指示Smooks在每個片斷結(jié)束時運用指定的FreeMarker模板(5.a)。該模板操作的結(jié)果綁定到beanId“csv_record_as_xml”(5.b)。

          FreeMarker模板(5.a)也可以直接在Smooks配置中定義(在<ftl:template></ftl:template>元素內(nèi)部),但在這個例子中我們將其定義在外部文件:

          <#assign csvRecord = .vars["csv-record"]> <#-- special assignment because csv-record has a hyphen -->

          <customer fname='${csvRecord.firstname}' lname='${csvRecord.lastname}' >

          <gender>${csvRecord.gender}<gender>

          <age>${csvRecord.age}<age>

          <nationality>${csvRecord.country}<nationality>

          <customer>

          以上的FreeMarker模板引用了“csv-record”片斷節(jié)點模型。(譯注:由于原文編輯錯誤,導致HTML代碼中雖有csv-record字樣,但在展示到瀏覽器中卻沒有出現(xiàn))

          Java綁定

          Smooks可以有效地被用來從任意所支持的源數(shù)據(jù)格式來生成Java對象模型。生成后的對象模型本身可以作為最終結(jié)果使用,也可以被用作模板操作的模型,即生成后的對象模型(存儲在bean上下文里)可供模板技術(就像運用節(jié)點模型一樣)使用。

          再次繼續(xù)我們的CSV實例。我們有一個消費者Java類,以及一個性別枚舉類型(已省略getter/setter):

          publicclass Customer {

          private String firstName;

          private String lastName;

          private Gender gender;

          privateint age;

          }



          publicenum Gender {

          Male,

          Female

          }

          從CSV流中生成一組這一消費者對象的Smooks配置會像是這樣:

          <xml version="1.0"?>

          <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"

          xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.1.xsd">



          (1)  <csv:reader fields="firstname,lastname,gender,age,country" separator="|" quote="'" skipLines="1"/>

          (2) <jb:bindings beanId="customerList" class="Java.util.ArrayList" createOnElement="csv-set">

          (2.a) <jb:wiring beanIdRef="customer"/>

          <jb:bindings>



          (3) <jb:bindings beanId="customer" class="com.acme.Customer" createOnElement="csv-record">

          <jb:value property="firstName" data="csv-record/firstName"/>

          <jb:value property="lastName" data="csv-record/lastName"/>

          <jb:value property="gender" data="csv-record/gender" decoder="Enum">

          (3.a) <jb:decodeParam name="enumType">com.acme.Genderjb:decodeParam>

          <jb:value>

          <jb:value property="age" data="csv-record/age" decoder="Integer"/>

          <jb:bindings>



          <smooks-resource-list>

          1. 配置(1)指示Smooks對所提供的配置使用CSV閱讀器。
          2. 配置(2)指示Smooks在遇到消息的開始時(該元素)創(chuàng)建一個ArrayList的實例,并將其綁定到beanId“customerList”的bean上下文中。我們想要將(2.a)實例的“customer”bean(3)裝配到這一ArrayList。
          3. 配置(3)指示Smooks在遇到每一元素的開時時創(chuàng)建一個Customer類的實例。每個元素都定義了一個值綁定,從事件流中選擇數(shù)據(jù)并將這一數(shù)據(jù)解碼后的值綁定到當前Customer實例的指定屬性中。配置(3.a)告訴Smooks對Gender屬性使用Enum解碼器。

          當然,上述分拆、轉(zhuǎn)換和路由用例的一個變體可能是將生成好的Customer對象路由到JMS隊列,而不是一個FreeMarker模板所產(chǎn)生的XML:

          <xml version="1.0"?>

          <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd"

          xmlns:csv="http://www.milyn.org/xsd/smooks/csv-1.1.xsd"

          xmlns:jms="http://www.milyn.org/xsd/smooks/jms-routing-1.1.xsd"

          xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.1.xsd">



          <params>

          <param name="stream.filter.type">SAXparam>

          params>



          <csv:reader fields="firstname,lastname,gender,age,country" separator="|" quote="'" skipLines="1"/>



          <jms:router routeOnElement="csv-record" beanId="customer" destination="xmlRecords.JMS.Queue"/>



           <jb:bindings beanId="customer" class="com.acme.Customer" createOnElement="csv-record">

          <jb:value property="firstName" data="csv-record/firstName"/>

          <jb:value property="lastName" data="csv-record/lastName"/>

          <jb:value property="gender" data="csv-record/gender" decoder="Enum">

          <jb:decodeParam name="enumType">com.acme.Genderjb:decodeParam>

          jb:value>

          <jb:value property="age" data="csv-record/age" decoder="Integer"/>

          jb:bindings>



           <smooks-resource-list>

          并且事情再復雜一點也沒關系,可以對每個csv記錄執(zhí)行多路由操作,可以將Customer對象路由到JMS隊列同時路由到FreeMarker產(chǎn)生的XML消息以歸檔。

          性能

          這一問題不可避免地一次次被提起。我們對Smooks進行了許多次的隨機基準測試,以下的小節(jié)就是我們得到的普遍結(jié)果。

          • Smooks核心過濾開銷: Smooks內(nèi)核使用SAX過濾器(使用Xerces作為XML閱讀器)對XML進行處理,在沒有配置訪問者邏輯的情況下,較使用相同SAX解析器直接進行的SAX處理增加了大概百分之五到十的開銷。
          • Smooks模板開銷: 在早期的Smooks版本中,為了對比“通過Smooks運用XSLT”和“單獨使用XSLT”的開銷,我們再次執(zhí)行了一些基準測試以期對其進行確定。Smooks當時(以及現(xiàn)在)僅通過DOM過濾器來支持XSLT。與基于DOM的XSLT應用相比,Smooks增加了百分之五到十五的開銷,準確值取決于XSL處理器。
          • Smooks Java綁定開銷:我們對于這一點的結(jié)果僅僅是基于跟一個主要的“XML到Java”開源綁定框架的對比。我們的發(fā)現(xiàn)是對于較小的消息(如小于10k),Smooks稍有些慢,但對于大一點的消息而言就快得多了。

          今天,Smooks正被應用于好些個任務關鍵的生產(chǎn)環(huán)境。每當我們收到任何關于性能的詢問時,其原因總是歸咎于某種配置問題(比如使執(zhí)行報告產(chǎn)生器一直保持開啟狀態(tài))。一旦將其解決,用戶總會對性能非常滿意。這雖然并非一個十分恰當?shù)淖C據(jù),但是它告訴了我們Smooks在性能方面不是“軟蛋”。

          總的來說,Smooks內(nèi)核是相當高效的,較標準的基于SAX的XML處理而言只增加了相對較低的開銷。在這以后,性能取決于所配置的訪問者邏輯,它的目的和效率表現(xiàn)。

          Smooks的下一步

          Smooks v1.2的首要目標是提供更多處理EDI消息的工具。我們同樣希望對某些更流行的EDI消息類型提供開箱即用的支持。

          如前所述,Smooks開發(fā)的另一重要工作將會是繼續(xù)JBoss Tools項目,構(gòu)建一個Smooks的Eclipse編輯器。

          總結(jié)

          希望這一文章能讓讀者對Smooks及其核心功能有個更好的了解。我們希望人們能下載Smooks,瞧一瞧看一看,并提供些反饋。

          查看英文原文:Structured Event Streaming with Smooks。

          中文原文地址: http://www.infoq.com/cn/articles/event-streaming-with-smooks

          posted on 2009-08-04 20:00 周銳 閱讀(1313) 評論(0)  編輯  收藏 所屬分類: Java 、XML
          主站蜘蛛池模板: 浮山县| 哈尔滨市| 贵德县| 仙桃市| 万年县| 辽阳市| 根河市| 湖南省| 和硕县| 南投市| 稷山县| 望奎县| 犍为县| 德格县| 日土县| 小金县| 甘孜县| 永胜县| 湄潭县| 紫金县| 广丰县| 平泉县| 和田市| 沅江市| 河间市| 资阳市| 江陵县| 报价| 西平县| 阿合奇县| 安顺市| 治县。| 塘沽区| 双流县| 漯河市| 曲靖市| 嘉义市| 海盐县| 德格县| 和平县| 天柱县|