一、
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:名為chitchatter的in-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)求。
總體流程:
- 客戶應(yīng)用向LoanBroker 貸款中介服務(wù) 發(fā)出 CustomerQuoteRequest消息 。
- LoanBroker 貸款中介服務(wù) 創(chuàng)建一個(gè) LoanQuoteRequest 消息,這是總線通用消息格式。
- Mule通過JMS向Credit Agency Gateway 征信所網(wǎng)關(guān) 發(fā)送該消息。
- 網(wǎng)關(guān)整理請(qǐng)求、調(diào)用CreditAgency EJB組件,RelectionMessageBuilder自動(dòng)將CreditProfile附加到LoanQuoteRequest 消息上 。
- Mule通過JMS向Lender Gateway貸方網(wǎng)關(guān) 發(fā)送該消息.
- 貸方網(wǎng)關(guān) 使用VM傳輸調(diào)用貸方服務(wù) .
- Mule通過JMS向Banking Gateway銀行網(wǎng)關(guān) 發(fā)送該消息.
- Banking Gateway銀行網(wǎng)關(guān) 通過Axis實(shí)現(xiàn)的SOAP調(diào)用銀行服務(wù).
- 每家銀行都把自己的貸款報(bào)價(jià)附加到請(qǐng)求中并通過應(yīng)答地址ReplyTo 發(fā)回LoanBroker 貸款中介服務(wù) 。應(yīng)答地址是由Banking Gateway銀行網(wǎng)關(guān) 提供的.
-
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);