Spring integration part2.5 Getting down to business

在之前的文章簡單討論了channel晕粪,message,大概了解了幾種endpoint埠对,通過一些簡單的配置分析,大概能夠串聯(lián)一些簡單的流程裁替。在這一章项玛,會討論transformer以及相關(guān)的一些endpoint,對一些流程更加熟悉弱判。

Domain-driven transformation

現(xiàn)在是面向?qū)ο蟮臅r代襟沮,類作為信息的模版又可以被看作是數(shù)據(jù)的模型,對象則是承載數(shù)據(jù)的載體昌腰。但是相較于用對象在系統(tǒng)間傳遞信息开伏,使用類文本的結(jié)構(gòu)能夠更方便的進行信息的傳遞,尤其是對于Spring integration這種用message作為載體的設計遭商,比如Xml固灵。那么必要的一點就是如何在整個流程的頭尾進行Domain和xml信息的轉(zhuǎn)換。這個流程可以簡單表述為:Domain object -marshallinh-> portable format(xml)-unmarshalling-> domain object劫流。使中間的處理流程使用方便處理的信息進行傳遞巫玻。另外順便說一句,xml是很典型的這類數(shù)據(jù)祠汇,不光是因為它本身結(jié)構(gòu)簡單仍秤,而且可以通過xslt文件或者xpath語句對其進行解讀和處理,十分的方便可很。另外诗力,可能出現(xiàn)其他的格式需求,比如json我抠,csv等等苇本,當然如果每一種格式之間都有transformer就會很混亂,所以其實比較好的是用xml格式作為中介菜拓,每一種格式只需要實現(xiàn)fromXml和ToXml就可以了瓣窄,減少了復雜度。

下面我們來解析一段配置并且介紹一些知識點:

<channel id="delayEvents"><queue/></channel>

<transformer input-channel ="flightDelayInput" ref="flightEventTransformer"

method="convertToDelayEvent" output-channel="delayEvents"/>

<context:component-scan base-package="siia.business"/>

<beans:bean class="siia.business.StubFlightScheduler"/>

這一段配置和上一章有些許不同尘惧,首先康栈,“flightDelayInput”這個channel并沒有配置(并不是我懶得打)如果沒有配置,那么Input channel會默默地自己生成。另外下面的context:component-scan 和bean和Spring的上配置有關(guān)啥么,這里沒有附著代碼部分登舞,但是在代碼里面有一些@注釋,各有各的意思悬荣,其中@Messagepont @Autowired 和bean配置完成了依賴注入菠秒,就是在都配置文件的時候創(chuàng)建依賴的對象并注入,而不用在代碼里面“create”氯迂。具體的知識請參考Spring的相關(guān)知識践叠。

另外,我們在前幾張說過兩個關(guān)鍵詞:解耦和易測嚼蚀。每一個Transformer都可以有其自己的Unit Test禁灼。用到了Junit的相關(guān)知識。確保每一個transformer轿曙,以及其他Endpoint能夠保證本身的可測性及質(zhì)量弄捕。

Transformer不單單包括類型間的轉(zhuǎn)換,還可以對header和payload進行處理导帝。

第一種就是Content enricher守谓,它的應用場景是對payload的內(nèi)容進行處理,比如判斷您单,合并和處理之類的斋荞。(當然如果是xml信息,使用xslt也能處理類似的情況)第二種是Header enricher虐秦,因為Adapter或者Gateway相比于Payload更關(guān)注header的信息平酿,甚至發(fā)送的郵件地址都需要從Payload中組裝而成,這個時候就需要從payload中提取所需要的信息并且整理塞進header中羡疗,以便后續(xù)使用染服。對于發(fā)郵件的這個情況Spring 3.0還支持一種更簡單的通過配置實現(xiàn)的方式:

<mail:header-enricher><mail:to expression="payload?.profile?.emailAddress"/></mail:header-enricher>

這里的?是一種對payload和profile的判斷叨恨。當然這種方法的缺點一個是測試的實現(xiàn)一個是不易讀。所以并不是簡單的就是最好的挖垛。

Message-driven services

上一部分介紹了消息進來何處去時候的第一或最后一步就是通過transformer進行轉(zhuǎn)換痒钝,在消息處理過程中呢,一般使用service activator這個component痢毒。先舉一個例子:

<service-activator input-channel="flightDelays" output-channel="statusUpdates" ref="flightStatusService" method="updateStatus"/>

<beans:bean id="flightStatusService" class="siia.business.SimpleFlightStatusService"/>

在之前章節(jié)簡單介紹過這種component送矩,兩個進出的channel,相關(guān)的類和方法哪替。bean是將siia.business.SimpleFlightStatusService的對象注入到類flightStatusService中栋荸。

我們考慮一種情況,就是一個service activator或者是其他的雙向的components,如果在調(diào)用的方法中存在返回值晌块,但是沒有配置output-channel會怎樣爱沟。這里還有一種解決方式就是在header中配置output-channel(當然這也是在處理過程中進行的,如下)匆背。

Message requestMessage = MessageBuilder.withPayload(someObject).setReplyChannel(replyChannelObject).build().

值得注意的是呼伸,如果一個Service有返回值,但是既沒有聲明output-channel钝尸,在message header中也沒有replyChannel括享,將會拋出Runtime exception。

Message publishing interceptors

消息攔截器珍促,可以理解為一個新的對流程的事件觸發(fā)機制铃辖。應用場景可以理解為,當一個狀態(tài)發(fā)生改變的時候猪叙,使所有相關(guān)的事物發(fā)生改變澳叉。聽起來象是一個Publisher信息發(fā)布者。上文涉及到Spring框架實現(xiàn)依賴注入的配置沐悦,這里用到則是另外一點成洗,AOP面向切面。就是這個攔截器并不存在于整個流程中藏否,而是設定在一個特定的時機瓶殃,可以理解為切面進行觸發(fā)。實現(xiàn)方式如如下代碼:

public class SimpleFlightStatusService implements FlightStatusService{

@Publisher(channel="statisticsChannel")

public FlightStatus updateStatus(@Payload FlightDelayEvent flightDelayEvent)

//更新DB中Status的數(shù)據(jù) //其它相關(guān)操作

return new FlightStatus();}

可以看出通過兩個注解副签,實現(xiàn)了設置觸發(fā)條件(channel="statisticsChannel")和獲取payload遥椿,文件內(nèi)容的效果。

Domain-drive Messaging Gateways

Gateway相當于設計模式的門面模式淆储,使得用戶不需要直接跟Spring Integration的api交互冠场,只需要跟自己定義的接口做交互就行了。用戶的業(yè)務代碼中不需要耦合進spring integration框架的代碼本砰。也就是說之前我們需要通過Spring Integration的api獲取Channel碴裙,并且向它發(fā)送message。而使用Gateway之后只需要知道我調(diào)用了一個Service点额,而他自己會shengchengmessage并發(fā)送到default channel中舔株。

舉一個例子:

public class FlightStatusNotificationPublisher{

private MailSender mailSender;

private JmsTemplate jmsTemplate;

public FlightStatusNotificationPublisher(MailSender mailSender,JmsTemplate jmsTemplate){

this.mailSender = mailSender;

this.jmsTemplate = jmsTemplate;

}

public void publishNotification(FlightStatusEvent event){

SimpleMailMessage mailMessage = null;//create maile Message

this.mailSender.send(mailMessage);

this,jmsTemplate.convertAndSend(event);

}}

這個類就是將要暴露的接口,在配置中將會配置Email和JMS的相關(guān)信息还棱,當調(diào)用publishNotification的時候,message就會發(fā)出载慈。

配置如下:

<gateway defult-request-channel="flightStatusNotifications" service-interface="siia.business.FlightStatusNotificationPublisher"/><!--聲明接口和默認端口-->

<object-to-string-transformer input-channel="flightStatusNotifications" output-channel="flightStatusStrings"/><!--將對象轉(zhuǎn)化為String-->

<publish-subscribe-channel id="flightStatusStrings"/><!--訂閱式的channel,可以觸發(fā)所有連接該channel的endpoint-->

<mail:outbound-channel-adapter channel="flightStatusStrings" mail-sender="mailSender"><!--Mail Sender的配置 Outbound Adapter-->

<jms:outbound-channel-adapter channel="flightStatusStrings" destination="flightStatusQueue"/><!--JMS Sender配置 Outbound Adapter-->

可以看出通過以上配置可以實現(xiàn)我們之前說到的功能珍手。

Chaining endpoints

是不是有的時候覺得配置channel比較煩办铡,因為雖然他沒有實現(xiàn)什么辞做,但是每兩個Endpoint之間就要有一個channel。那么寡具,有一種情況我們可以不配置這些channel秤茅,就是很多endpoint處于連續(xù),單流程(無分支)的情況晒杈,可以理解為整個流程可以在一個transaction之內(nèi)完成嫂伞,那么我們能將這樣的一段flow稱之并配置成一個chain,配置如下:

<chain input-channel="passengers">

<transformer ref="passengerProfileEnricher" method="addProfileInAvailable"/>

<mail:header-enricher><mail:to expression="payload?.profile?.emailAddress"/></mailheader-enricher>

<transformer ref="flightDelayEmailGenerator" method="generateEmail"/>

<mail:outbound-channel-adapter mail-sender="mailSender"/>

</chain>

這一段配置就將transformer,email-richer,transformer,email-sender串在了一起拯钻,省去了很多配置帖努。并且這樣寫最大的好處就是一眼能夠看出這是一個整體,一串流程粪般,更易讀拼余。

小結(jié)

這一部分我們介紹了比較常用的component,transformer。然后我們還了解了一些在Spring Integration中的注解亩歹,AOP思想匙监。接觸了消息攔截器,發(fā)布器和Gatway小作。知道了如何對單獨的模塊進行testcase的編碼亭姥。還學習到了非常有用且易用的chain結(jié)構(gòu)。通過一些簡單的配置和示例能夠更容易的體會其中的用法顾稀。接下來我們還會探索更多有用的endpoint或者其他結(jié)構(gòu)达罗。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市静秆,隨后出現(xiàn)的幾起案子粮揉,更是在濱河造成了極大的恐慌,老刑警劉巖抚笔,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扶认,死亡現(xiàn)場離奇詭異,居然都是意外死亡殊橙,警方通過查閱死者的電腦和手機辐宾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛀柴,“玉大人螃概,你說我怎么就攤上這事「爰玻” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵训貌,是天一觀的道長制肮。 經(jīng)常有香客問我冒窍,道長,這世上最難降的妖魔是什么豺鼻? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任综液,我火速辦了婚禮,結(jié)果婚禮上儒飒,老公的妹妹穿的比我還像新娘谬莹。我一直安慰自己,他們只是感情好桩了,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布附帽。 她就那樣靜靜地躺著,像睡著了一般井誉。 火紅的嫁衣襯著肌膚如雪蕉扮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天颗圣,我揣著相機與錄音喳钟,去河邊找鬼。 笑死在岂,一個胖子當著我的面吹牛奔则,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔽午,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼易茬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祠丝?” 一聲冷哼從身側(cè)響起疾呻,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎写半,沒想到半個月后岸蜗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡叠蝇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年璃岳,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悔捶。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡铃慷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蜕该,到底是詐尸還是另有隱情犁柜,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布堂淡,位于F島的核電站馋缅,受9級特大地震影響扒腕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萤悴,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一瘾腰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧覆履,春花似錦蹋盆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至柳沙,卻和暖如春岩灭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赂鲤。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工噪径, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人数初。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓找爱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泡孩。 傳聞我的和親對象是個殘疾皇子车摄,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容