一、Hello World (主要演示了兩個(gè)service component鏈?zhǔn)胶献魈幚硪粭l消息和消息格式轉(zhuǎn)換
1、示例翻譯:
  展示了如何配置多個(gè)service components——它們與一個(gè)請(qǐng)求交互(就是說二者合作以鏈?zhǔn)椒绞较群筇幚硪粋€(gè)請(qǐng)求消息,處理的方式是添加消息的內(nèi)容),以及如何管理事件轉(zhuǎn)換(所謂事件就是消息,這里的事件轉(zhuǎn)換是指消息格式的轉(zhuǎn)換,比如從stdio標(biāo)準(zhǔn)輸入中輸入的字符串轉(zhuǎn)換為一個(gè)java bean對(duì)象以及不同java bean之間的轉(zhuǎn)換)。這個(gè)例子還使用了屬性文件來配置i18n國際化的消息文字。還有演示了出站過濾路由。




  使用了兩個(gè)類也就是兩個(gè)service component組件來先后處理消息,第一個(gè)是Greeter 類,它的greet()方法 使用LocalMessage 來從上面提到的屬性文件獲取greeting問候語,然后把問候語"Hello"加到你在控制臺(tái)輸入的名字之前(這樣它就第一次修改了消息的內(nèi)容)。第二個(gè)是ChitChatter類,它的chat方法 把", how are you?"加到消息內(nèi)容之后(這樣它又一次修改了消息內(nèi)容):


<service name="GreeterUMO">  
  
<inbound>  
    
<stdio:inbound-endpoint system="IN" transformer-refs="StdinToNameString"/>  
  
</inbound>  
  
<component class="org.mule.example.hello.Greeter"/>  
  
<outbound>  
    
<filtering-router>  
      
<vm:outbound-endpoint path="chitchatter"/>  
      
<payload-type-filter expectedType="org.mule.example.hello.NameString"/>  
    
</filtering-router>  
  
</outbound>  
</service>  
流程是這樣的:命令行接受用戶輸入 -> StdinToNameString轉(zhuǎn)換器將字符串格式的消息轉(zhuǎn)換為NameString類型的java bean -> 消息交給Greeter組件處理:把"Hello"加到了消息內(nèi)容之前 -> 處理之后的消息被發(fā)往chitchatter隊(duì)列 -> ChitChatUMO服務(wù)組件)StdinToNameString轉(zhuǎn)換器在之前就定義好了:

<custom-transformer name="StdinToNameString"  
 class
="org.mule.example.hello.StdinToNameString"/>

  注意: Mule是依靠反射獲知Greeter內(nèi)部各個(gè)方法需要的傳參類型,然后再根據(jù)目前消息格式調(diào)用正確的消息處理方法。Greeter處理完消息后、mule把消息分發(fā)到了端點(diǎn):vm://chitchatter:名為chitchatterin-memory queue內(nèi)存隊(duì)列。ChitChatUMO服務(wù)組件正在監(jiān)聽這個(gè)隊(duì)列(也就是說chitchatter隊(duì)列是 GreeterUMO的輸出、ChitChatUMO的輸入,這樣來使得兩個(gè)服務(wù)組件先后處理一條消息)

<service name="ChitChatUMO">  
  
<inbound>  
    
<vm:inbound-endpoint path="chitchatter" transformer-refs="NameStringToChatString"/>  
  
</inbound>  
  
<component class="org.mule.example.hello.ChitChatter"/>  
  
<outbound>  
    
<pass-through-router>  
      
<stdio:outbound-endpoint system="OUT" transformer-refs="ChatStringToString" />  
    
</pass-through-router>  
  
</outbound>  
</service>  

ChitChatUMO服務(wù)組件又配置了兩個(gè)轉(zhuǎn)換器:NameStringToChatString、ChatStringToString。ChitChatter組件類的輸入?yún)?shù)為 ChatString 類型,所以NameStringToChatString轉(zhuǎn)換器將消息格式從NameString轉(zhuǎn)為 ChatString、然后再調(diào)用 ChitChatter組件(流程:GreeterUMO -> vm://chitchatter -> NameStringToChatString -> ChitChatter -> ChatStringToString -> System.out)
注意Java bean是不含有任何路由邏輯的, Mule配置文件將它們組織到一起,任何已有的pojo、web services都可以照此辦理并在它們之間傳輸消息。


、Stock Quote (演示了如何調(diào)用ASPX web service、使用XSLT轉(zhuǎn)換、反序列化StockQuote Java bean以及使用REST和SOAP調(diào)用服務(wù)。例子需要訪問互聯(lián)網(wǎng)上的公共.NET服務(wù)、主要是咱也不知道人家都有哪些股票代碼有數(shù)據(jù)。源碼就不看了)

    1、示例翻譯:通過System.in接收股票代碼、調(diào)用StockQuote服務(wù)、通過XSLT轉(zhuǎn)換器將返回結(jié)果轉(zhuǎn)換格式、通過XmlToObject轉(zhuǎn)換器再將結(jié)果轉(zhuǎn)換為StockQuote類型、隨后將股票報(bào)價(jià)打印到System.out

  (例子用到了類似spring的屬性占位符特性來從配置文件取得一些信息、配置多個(gè)轉(zhuǎn)換器并“串聯(lián)”起來、其中還用到xslt轉(zhuǎn)換器)

<model name="Sample-Rest">  
    
<service name="HTTPPostSample">  
      
<inbound>  
        
<vm:inbound-endpoint path="stockquote"  
               responseTransformer-refs
="ToString XmlDecoder Xslt XmlToObject"/>  
      
</inbound>  
      
<http:rest-service-component  
               
serviceUrl="http://www.webservicex.net/stockquote.asmx/GetQuote"  
               httpMethod
="POST">  
        
<http:payloadParameterName value="symbol"/>  
      
</http:rest-service-component>  
    
</service>  
  
</model>  


配置當(dāng)中還用到所謂的REST service component , 它使用了REST服務(wù)包裝器代理了一個(gè)REST服務(wù)、這樣使得該service服務(wù)看上去似乎是本地的component組件一般(和CXF的web服務(wù)包裝器差不多),REST服務(wù)包裝器有一些配置屬性:serviceUrl就是 訪問REST服務(wù)的url、payloadParameterName是傳參名 ,本例中只有一個(gè)參數(shù)"symbol"——股票代碼、httpMethod是方法名 ——GET或POST。

 

  我隨便傳了個(gè)代碼過去返回了無數(shù)據(jù)的xml:

<string>  
<StockQuotes><Stock><Symbol>002339</Symbol><Last>0.00</Last><Date>N/A</Date><Time>N/A</Time><Change>N/A</Change><Open>N/A</Open><High>N/A</High><Low>N/A</Low><Volume>N/A</Volume><MktCap>N/A</MktCap><PreviousClose>N/A</PreviousClose><PercentageChange>N/A</PercentageChange><AnnRange>N/A - N/A</AnnRange><Earns>N/A</Earns><P-E>N/A</P-E><Name>002339</Name></Stock></StockQuotes>  
</string>  

Web Service版和REST版原理類似,只是服務(wù)配置是不同的。Web Service版顯式配置了outbound pass-through路由,它將輸入從一個(gè)endpoint直接傳輸?shù)給utbound Axis endpoint,不作任何改變或處理。另外outbound endpoint向Stock Quote service股票報(bào)價(jià)服務(wù)請(qǐng)求時(shí)是帶參數(shù)的。
<model name="Sample-SOAP">  
  
<service name="serviceProxy">  
    
<inbound>  
      
<vm:inbound-endpoint path="stockquote"  
                  responseTransformer-refs
="ToString XmlDecoder Xslt XmlToObject"/>  
    
</inbound>  
    
<outbound>  
      
<pass-through-router>  
        
<axis:outbound-endpoint address="http://www.webservicex.net/stockquote.asmx?method=GetQuote"  
                  responseTransformer-refs
="XmlDecoder Xslt XmlToObject"  
                  soapAction
="[methodNamespace][method]">  
          
<axis:soap-method method="qname{GetQuote:http://www.webserviceX.NET/}">  
            
<axis:soap-parameter parameter="symbol" type="string" mode="IN"/>  
            
<axis:soap-parameter parameter="GetQuoteResult" type="string" mode="OUT"/>  
          
</axis:soap-method>  
        
</axis:outbound-endpoint>  
      
</pass-through-router>  
    
</outbound>  
  
</service>  
</model>  

三、Error Handler (演示了如何使用Spring beans作為service component以及向多個(gè)出站endpoint發(fā)布消息,使用了文件監(jiān)控inbound+郵件outbound)
示例包含兩個(gè)services: ExceptionManager 異常管理器 和 BusinessErrorManager業(yè)務(wù)錯(cuò)誤管理器。



  BusinessErrorManager是個(gè)簡(jiǎn)單的service,它通過JMS接收業(yè)務(wù)異常消息并將消息記錄到控制臺(tái),以此模仿真實(shí)的異常處理應(yīng)用。

  ExceptionManager接收異常消息并根據(jù)異常消息的類型進(jìn)行某些處理動(dòng)作。例如如果收到致命異常則會(huì)向系統(tǒng)管理員發(fā)送郵件;收到標(biāo)準(zhǔn)系統(tǒng)異常則寫入本地文件log,例子演示的不是異常處理、演示的是:

  • 所有的service components都是以spring bean的形式在一個(gè)mule配置文件當(dāng)中配置的。
  • error manager擁有多個(gè)outbound endpoints出站端點(diǎn),例子演示了消息如何發(fā)布到不同端點(diǎn)。
  • 消息是Java對(duì)象形式,并且需要在XML形式之間互相轉(zhuǎn)換。例子演示了鏈接多個(gè)轉(zhuǎn)換器。


     <spring:bean id="errorManager" class="org.mule.example.errorhandler.ErrorManager">
            
    <spring:property name="handlers">
                
    <spring:list>
                    
    <spring:ref local="fatalHandler"/>
                    
    <spring:ref local="defaultHandler"/>
                    
    <spring:ref local="businessHandler"/>
                
    </spring:list>
            
    </spring:property>
        
    </spring:bean>


        <model name="errorhandler-test">
            
    <service name="Error Manager">
                
    <inbound>
                    
    <inbound-endpoint address="file://./test-data/in"
                                   transformer-refs
    ="XMLToExceptionBean ExceptionBeanToErrorMessage">
                    
                        
    <file:filename-wildcard-filter pattern="*.xml"/>
                    
    </inbound-endpoint>
                
    </inbound>
                
                
    <pooled-component>
                    
    <prototype-object class="org.mule.example.errorhandler.ErrorManager">
                        
    <properties>
                            
    <spring:entry key="handlers">
                                
    <spring:list>
                                    
    <spring:ref local="fatalHandler"/>
                                    
    <spring:ref local="defaultHandler"/>
                                    
    <spring:ref local="businessHandler"/>
                                
    </spring:list>
                            
    </spring:entry>
                        
    </properties>
                     
    </prototype-object>
                
    </pooled-component>

                
    <outbound>
                    
    <filtering-router>
                        
    <file:outbound-endpoint path="test-data/exceptions"
                                                outputPattern
    ="Exception-[UUID].xml"
                                                transformer-refs
    ="ErrorMessageToExceptionBean ExceptionBeanToXML"/>
                        
    <!-- Check ErrorMessage.getThrowable() exception type -->
                        
    <expression-filter evaluator="groovy" expression="payload.throwable instanceof org.mule.api.DefaultMuleException"/>
                    
    </filtering-router>
                    
                    
    <filtering-router>
                        
    <smtp:outbound-endpoint user="${smtp.username}" password="${smtp.password}"
                                                host
    ="${smtp.host}" port="${smtp.port}"
                                                to
    ="${email.toAddress}" from="${email.fromAddress}"
                                                subject
    ="${email.subject}"
                                                transformer-refs
    ="ErrorMessageToExceptionBean ExceptionBeanToXML StringToEmailMessage"/>
                        
    <!-- Check ErrorMessage.getThrowable() exception type -->
                        
    <expression-filter evaluator="groovy" expression="payload.throwable instanceof org.mule.api.lifecycle.FatalException"/>
                    
    </filtering-router>
                    
                    
    <filtering-router>
                        
    <outbound-endpoint address="jms://exception.queue"
                                       transformer-refs
    ="ErrorMessageToExceptionBean ExceptionBeanToXML ObjectToJMSMessage"/>
                        
    <!-- Check ErrorMessage.getThrowable() exception type -->
                        
    <expression-filter evaluator="groovy" expression="payload.throwable instanceof org.mule.example.errorhandler.exceptions.BusinessException"/>
                    
    </filtering-router>
                    
                    
    <custom-catch-all-strategy class="org.mule.routing.LoggingCatchAllStrategy"/>
                
    </outbound>
            
    </service>

四、Loan Broker (基于Enterprise Integration Patterns book 一 EIP書中的例子 ,mule不鳥JBI和SCA,唯遵SEDA和EIP,有個(gè)性)
 Loan Broker貸款中介(也叫l(wèi)oan agent service)是mule的主要演示例子,顧名思義,就是客戶向銀行申請(qǐng)貸款的故事。先看一下背景知識(shí):

  以往的貸款請(qǐng)求流程如下圖


  1) 客戶customer 向不同的銀行bank 發(fā)起請(qǐng)求搜尋最優(yōu)利率。

  2) 每家銀行都要向客戶詢問社保號(hào)碼ss、貸款數(shù)量以及期限。

  3) 每家銀行都要對(duì)該客戶做信用背景調(diào)查:通常是咨詢征信所credit bureau (通過征信中介credit  agency ),最后銀行才能根據(jù)這些信息發(fā)放貸款。

  4) 客戶接收到所有銀行的反饋以后,從中選擇一家最好的,比如說利率最低

加貸款中介以后,這個(gè)處理流程可以更加自動(dòng)化、允許客戶在線獲取更多銀行的實(shí)時(shí)反饋,耗時(shí)要比一家一家詢問少得多:

  1) 接收到客戶請(qǐng)求以后,loan broker貸款中介從征信所獲取該客戶的信用信息。

  2) 替該客戶向貸方服務(wù)lender service 列出的所有銀行發(fā)出貸款請(qǐng)求(例子中這個(gè)服務(wù)啥也沒做只是個(gè)意思)

  3) 將反饋的貸款額度信息打包發(fā)送回用戶供選擇(例子中就是選擇返回利率最低的那家銀行)


這其中的角色包括

  1、貸款中介服務(wù)http/rest(接收客戶的http貸款請(qǐng)求,包含社保號(hào)、貸款額、期限并負(fù)責(zé)相應(yīng)放貸信息)。

  2、征信所服務(wù)EJB(由貸款中介公司管理的EJB外部服務(wù),做信用檢查的,暴露一個(gè)名為creditAgency的EJB的getCreaditProfile方法)

  3、征信所網(wǎng)關(guān)(例子中的網(wǎng)關(guān)做的事情都是:在JMS消息總線和 外部應(yīng)用或服務(wù)/征信所服務(wù)應(yīng)用 之間整理請(qǐng)求)

  4、貸方服務(wù)VM(根據(jù)客戶的資信評(píng)分等信息選擇請(qǐng)貸的銀行,本地pojo組件,決定請(qǐng)求哪幾家銀行)

  5、貸方網(wǎng)關(guān)(在消息總線到貸方服務(wù)應(yīng)用之間整理請(qǐng)求)

  6、銀行網(wǎng)關(guān)(向多家銀行分發(fā)貸款請(qǐng)求)

  7、還有幾家銀行bank(soap協(xié)議的消息服務(wù)、為了簡(jiǎn)化、所有銀行暴露同樣的ws接口。當(dāng)然你也可以配置不同接口的多家銀行)。

都算是應(yīng)用,以往的應(yīng)用之間通訊是點(diǎn)對(duì)點(diǎn),客戶自己去一家一家調(diào)用銀行服務(wù)、所有銀行都一遍一遍地調(diào)用征信所。而loanBroker就相當(dāng)于我們的ESB,加入loanBroker以后就不再是點(diǎn)對(duì)點(diǎn)而是點(diǎn)對(duì)面,ESB就是面、覆蓋了征信所、所有銀行及各個(gè)網(wǎng)關(guān)的一個(gè)門面(這么看ESB蠻像一個(gè)fasade的嘛),這個(gè)門面替應(yīng)用擺平一切,你只要說我要貸款!、其他的如你的資信評(píng)級(jí)、你都要請(qǐng)求誰、你的請(qǐng)求還需要依賴什么都包辦,有事您只管說句話就得。

  例子涉及異步的請(qǐng)求/響應(yīng)處理模型;對(duì)JMS、http/rest、vm、soap、EJB各種協(xié)議的調(diào)用;把bank暴露為ws??偩€中的消息用LoanQuoteRequest 代表,本例中這是個(gè)javaBean格式,但是實(shí)際中往往是個(gè)xml格式(用了ESB,我發(fā)現(xiàn)對(duì)消息這個(gè)東東來說格式是五花八門的:javabean pojo、xml、http參數(shù)、stdio、soap甚至json...)

 

  loan broker的示例包含ESB和ESN兩種布局的版本,含義參見Mule Topologies的5種拓?fù)洳季郑?/p>

  ESB、ESN企業(yè)服務(wù)網(wǎng)、對(duì)等網(wǎng)(這不又成了點(diǎn)對(duì)點(diǎn)了么,不推薦)、C/S以hub為中心的輻射方式(可能性能有問題,不推薦)、管道方式(服務(wù)編排?)



1、示例翻譯:

  Loan Broker ESB基于當(dāng)前的Loan Broker示例 但是實(shí)現(xiàn)了一個(gè)完整的ESB架構(gòu),該例子演示了如何使用HTTP/REST、 Web Services、EJB、JMS,他是根據(jù)典型ESB實(shí)現(xiàn)來配置的。

  Loan Broker ESB使用了JMS消息總線以提供在不同組件和應(yīng)用間的公共消息通道:




組件:

  1、Loan Broker Service貸款中介服務(wù) :接收貸款請(qǐng)求(信息包括SS社保號(hào)碼、貸款額度、期限)并負(fù)責(zé)收集放貸反饋向客戶反饋。

  2、Credit Agency Service征信所服務(wù) :外部服務(wù)提供者、它對(duì)客戶的授信進(jìn)行檢驗(yàn)以確保合理的放貸額度。

  3、Credit Agency Gateway征信所網(wǎng)關(guān) :在消息總線和征信所應(yīng)用之間整理請(qǐng)求。

  4、Lender Service貸方服務(wù) :基于客戶的資信評(píng)分,放貸額度和期限,由貸方服務(wù)選擇請(qǐng)求貸款的銀行。

  5、Lender Gateway貸方網(wǎng)關(guān) :從消息總線到貸方應(yīng)用之間整理請(qǐng)求。

  6、Banking Gateway銀行網(wǎng)關(guān) :基于貸方列表、向一家或多家銀行分發(fā)貸款請(qǐng)求。

總體流程:

  1. 客戶應(yīng)用向LoanBroker 貸款中介服務(wù) 發(fā)出 CustomerQuoteRequest消息 。
  2. LoanBroker 貸款中介服務(wù) 創(chuàng)建一個(gè) LoanQuoteRequest 消息,這是總線通用消息格式。
  3. Mule通過JMS向Credit Agency Gateway 征信所網(wǎng)關(guān) 發(fā)送該消息。
  4. 網(wǎng)關(guān)整理請(qǐng)求、調(diào)用CreditAgency EJB組件,RelectionMessageBuilder自動(dòng)將CreditProfile附加到LoanQuoteRequest 消息上 。
  5. Mule通過JMS向Lender Gateway貸方網(wǎng)關(guān) 發(fā)送該消息.
  6. 貸方網(wǎng)關(guān) 使用VM傳輸調(diào)用貸方服務(wù) .
  7. Mule通過JMS向Banking Gateway銀行網(wǎng)關(guān) 發(fā)送該消息.
  8. Banking Gateway銀行網(wǎng)關(guān) 通過Axis實(shí)現(xiàn)的SOAP調(diào)用銀行服務(wù).
  9. 每家銀行都把自己的貸款報(bào)價(jià)附加到請(qǐng)求中并通過應(yīng)答地址ReplyTo 發(fā)回LoanBroker 貸款中介服務(wù) 。應(yīng)答地址是由Banking Gateway銀行網(wǎng)關(guān) 提供的.
  10. LoanBroker 貸款中介服務(wù) 的ResponseRouter響應(yīng)路由接收對(duì)應(yīng)答地址 的響應(yīng),它選擇最低利率并返回客戶。


本例中,消息總線上的通用消息格式是java bean格式。一般情況下如JMS規(guī)范要求總線內(nèi)的通用消息是xml格式,但是mule允許你使用任何數(shù)據(jù)格式,兩種格式各有優(yōu)缺,xml的文本消息允許你方便的直接實(shí)施xslt轉(zhuǎn)換器之類,bean方式在component中更便于編碼處理,兩種方式也都方便用路由器去根據(jù)消息內(nèi)容做路由判斷。我們先來定義這個(gè)消息bean:LoanQuoteRequest(org.mule.example.loanbroker.messages.LoanBrokerQuoteRequest):
public class LoanBrokerQuoteRequest implements Serializable//由于需要在jms通道傳輸所以需要實(shí)現(xiàn)序列化  
{  
    
/** 
     * Serial version 
     
*/  
    
private static final long serialVersionUID = 46866005259682607L;  
  
    
/** The customer request  
     * The request contains Customer info and loan amount and duration 
*/  
    
private CustomerQuoteRequest customerRequest;  
  
    
/** credit profile for the customer  */  
    
private CreditProfile creditProfile;  
  
    
/** A list of lenders for this request */  
    
private Bank[] lenders;  
  
    
/** A loan quote from a bank */  
    
private LoanQuote loanQuote;  
      
    
//get/set方法  
}  

 客戶的初始請(qǐng)求觸發(fā)整個(gè)事件處理流,客戶使用瀏覽器以htt協(xié)議請(qǐng)求mule rest服務(wù),這個(gè)服務(wù)當(dāng)然得向外暴露,暴露的方式就是配置貸款中介端點(diǎn) (CustomerRequestsREST)
<endpoint name="CustomerRequestsREST" address="jetty:rest://localhost:8888/loanbroker" /> 

 這句話的配置含義:

 1、內(nèi)嵌Jetty servlet引擎

 2、mule啟動(dòng)jetty在8888端口上監(jiān)聽rest請(qǐng)求

 3、把rest servlet綁定到/loanbroker上下文
來自客戶的初始rest請(qǐng)求格式為:

http://localhost:8888/loanbroker/?name=Ross+Mason&ssn=1234& loanAmount=10000&loanDuration=24 

貸款中介端點(diǎn) 以http參數(shù)形式接收下來,需要轉(zhuǎn)換為CustomerQuoteRequest對(duì)象,所以增加了一個(gè)自定義轉(zhuǎn)換器:

<custom-transformer name="RestRequestToCustomerRequest" class="org.mule.example.loanbroker.transformers.RestRequestToCustomerRequest" />  

這個(gè)轉(zhuǎn)換器要用在貸款中介端點(diǎn) 上,在貸款中介服務(wù)的入站inbound配置上、入站端點(diǎn)endpoint引用了貸款中介端點(diǎn)(CustomerRequestsREST)、同時(shí)也引用了這個(gè)轉(zhuǎn)換器。也就是說從貸款中介端點(diǎn) 上接收的rest請(qǐng)求都直接用這個(gè)轉(zhuǎn)換器予以轉(zhuǎn)換:

<service name="LoanBroker"><!--貸款中介服務(wù)-->  
            
<description>  
                The LoanBroker service is our 'entry' service that accepts requests from the outside world  
            
</description>  
            
<inbound>  
                
<inbound-endpoint ref="CustomerRequestsREST" transformer-refs="RestRequestToCustomerRequest" />  
    






@import url(http://www.tkk7.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);