發(fā)布于:2021-01-16 14:11:16
0
1738
0
自2007年由Apache社區(qū)創(chuàng)建以來(lái),開(kāi)源集成框架apachecamel已經(jīng)成為開(kāi)發(fā)人員的最愛(ài)。它被認(rèn)為是設(shè)計(jì)SOA/集成項(xiàng)目和處理復(fù)雜的企業(yè)集成用例的關(guān)鍵技術(shù)。本文是本系列文章的第一部分,它將揭示框架如何從特定領(lǐng)域的語(yǔ)言生成交換發(fā)生的路徑,如何根據(jù)所選的模式進(jìn)行處理,以及最終如何進(jìn)行集成。
簡(jiǎn)介
從一般的觀點(diǎn)來(lái)看,設(shè)計(jì)集成體系結(jié)構(gòu)并不是一項(xiàng)顯而易見(jiàn)的任務(wù),即使您想要使用的技術(shù)和框架相對(duì)容易理解和實(shí)現(xiàn)。困難在于消息的數(shù)量、要應(yīng)用的轉(zhuǎn)換、交換的同步性或異步性、順序或并行運(yùn)行的進(jìn)程,當(dāng)然還有對(duì)在多個(gè)jvm中運(yùn)行的此類項(xiàng)目的監(jiān)視。
在傳統(tǒng)的Java應(yīng)用程序中,我們從類調(diào)用方法,同時(shí)傳遞和/或返回對(duì)象。被調(diào)用的方法是鏈?zhǔn)降?,?duì)象傳輸信息,有時(shí)在事務(wù)中登記,但總是部署在同一個(gè)Java容器中(Web、JEE、Standalone)。除非我們必須調(diào)用外部系統(tǒng)或集成遺留應(yīng)用程序、RDBMS等,否則大多數(shù)調(diào)用都是本地同步完成的。
如果一個(gè)服務(wù)想要可重用,它需要被打包,在庫(kù)中進(jìn)行版本控制,并與將使用它的項(xiàng)目通信。這種方法適用于由內(nèi)部開(kāi)發(fā)團(tuán)隊(duì)維護(hù)的項(xiàng)目,在這些項(xiàng)目中,成本可以由IT部門支持,但它會(huì)遇到不同的問(wèn)題,并且大多數(shù)情況下要求我們使用相同的編程語(yǔ)言或特定技術(shù)來(lái)互連流程(RPC、IIOP等),即部署代碼的容器。
圖1:SOA
為了允許應(yīng)用程序在沒(méi)有此類約束的情況下獨(dú)立開(kāi)發(fā),必須在負(fù)責(zé)使用它的服務(wù)的請(qǐng)求/消息的發(fā)布者之間促進(jìn)解耦。這種新的體系結(jié)構(gòu)范例稱為面向服務(wù)的體系結(jié)構(gòu),它使用傳輸層在系統(tǒng)之間交換信息。SOA的一個(gè)直接好處是促進(jìn)基于契約的方法來(lái)定義應(yīng)用程序之間公開(kāi)的服務(wù),并根據(jù)“治理規(guī)則”來(lái)管理它們。
SOA方法已經(jīng)能夠聯(lián)合不同的團(tuán)隊(duì),解決圍繞更復(fù)雜項(xiàng)目開(kāi)發(fā)的問(wèn)題。這種IT轉(zhuǎn)型是必需的,因?yàn)楣拘枰`活地適應(yīng)市場(chǎng)需求,信息必須實(shí)時(shí)提供,業(yè)務(wù)適應(yīng)需要現(xiàn)有的遺留系統(tǒng)和后臺(tái)系統(tǒng)的支持。
雖然SOA理念已被廣泛采用,但掌握XML、XDS模式、Web服務(wù)和業(yè)務(wù)流程引擎的學(xué)習(xí)曲線、橫向團(tuán)隊(duì)的創(chuàng)建和管理,管理服務(wù)所需的治理和所需的技能無(wú)疑是解釋SOA為何仍難以被公司采用的因素。此外,資訊科技部門不僅關(guān)心推廣和管理網(wǎng)頁(yè)服務(wù)和注冊(cè)處,而且也關(guān)心不同系統(tǒng)之間的互聯(lián)、交換、轉(zhuǎn)換和驗(yàn)證資訊。在闡述SOA原則時(shí),IT工作的這個(gè)集成方面被完全“低估”了。
企業(yè)集成模式
2005年,Gregory Hope和Bobby Wolf出版了一本名為《企業(yè)集成模式》的書(shū),他們不僅花時(shí)間描述復(fù)雜的用例,還定義了詞匯表、語(yǔ)法和設(shè)計(jì)圖標(biāo)來(lái)表達(dá)IT部門必須解決的復(fù)雜集成模式。這本書(shū)改變了開(kāi)發(fā)團(tuán)隊(duì)(業(yè)務(wù)/功能分析人員、數(shù)據(jù)建模人員和開(kāi)發(fā)人員)協(xié)作設(shè)計(jì)集成/SOA項(xiàng)目的方式。討論的重點(diǎn)不僅僅是服務(wù)、XML的結(jié)構(gòu)和業(yè)務(wù)流程的設(shè)想,還包括如何使用模式來(lái)解決集成用例(聚合、拆分、過(guò)濾、基于內(nèi)容的路由、動(dòng)態(tài)路由)。這本書(shū)利用參與者來(lái)實(shí)現(xiàn)更靈活的編程方法。為了支持本書(shū)中描述的EIP并幫助開(kāi)發(fā)人員解決集成用例,apachecamel集成Java框架創(chuàng)建于5年前。
EIP設(shè)計(jì)圖標(biāo)
發(fā)現(xiàn)Apache
表示聚合或路由的EIP模式,這要求我們使用語(yǔ)言“表示”它們。這種語(yǔ)言不是一種新的編程語(yǔ)言,而且是一種特定于某個(gè)領(lǐng)域的語(yǔ)言,它充分地描述了所選領(lǐng)域(集成)的問(wèn)題。apachecamel是一個(gè)Java集成框架,它支持omainSspecificLanguage(aka)。DSL;有關(guān)更多信息,請(qǐng)參閱Camel文檔)使用面向?qū)ο蟮恼Z(yǔ)言,如Java、Scala、Groovy等。不需要解析器、編譯器或解釋器,而是命令列表、按順序排列的指令:
instruction1().instruction2()....instructionN();
apachecamel也被定義為“中介和路由”引擎。讓我們想想全球道路網(wǎng):我們可以在城市和首都之間運(yùn)輸不同類型和大小的車輛,運(yùn)送不同出身、膚色、年齡、性別的乘客。根據(jù)交通狀況,可以調(diào)整行程,使用替代道路。同樣,Apache Camel沿著路徑傳輸消息。
from("Brussels") .to("Paris"); // Transport passengers from Brussels Capital to Paris
每個(gè)Camel路由都以from指令開(kāi)始,這一指令特別重要,因?yàn)樗洚?dāng)使用者,并根據(jù)它是被觸發(fā)(“事件驅(qū)動(dòng)體系結(jié)構(gòu)”)還是能夠定期讀取數(shù)據(jù)(“輪詢體系結(jié)構(gòu)”)發(fā)揮特定的作用。使用者是一個(gè)工廠,每當(dāng)接收到數(shù)據(jù)時(shí),就會(huì)通過(guò)Apache Camel路由創(chuàng)建和傳輸“消息”。
當(dāng)然,apachecamel根本不在路線上運(yùn)輸“乘客”,而是運(yùn)輸“信息”。這些消息將通過(guò)一系列步驟,即處理器來(lái)轉(zhuǎn)換、驗(yàn)證、格式化、豐富所接收信息的內(nèi)容。該框架提供了不同的處理器,這些處理器經(jīng)過(guò)專門化(Bean、Log),以簡(jiǎn)化我們希望應(yīng)用的操作,如下面的代碼:
from("Brussels") .bean("Border","validPassport") .log("Passport has been controlled") .bean("Border","controlTicket") .to("log:travel://LogLevel=INFO" + "Ticket has been controlled") .to("Paris");
放置在“from”后面的每個(gè)處理器傳遞信息,并像火車車廂一樣“形成”一條鏈,如下圖所示:
from("") ... .to("log:travel://LogLevel=INFO" + "Ticket has been controlled") // .to("file:///outputDirectoryWhereFileWillbeCreated") // .to("http://www.google.be?doASearch") // Call External HTTP Server .to("jms://queue:outputQueue; // Response received is published in a queue
然而,某些處理器會(huì)產(chǎn)生一條消息,Camel會(huì)將該消息發(fā)送到服務(wù)器(SMTP、FTP)、應(yīng)用程序(RDBMS)、代理(JMS)和另一個(gè)Camel路由(DIRECT、SEDA、VM),并且在某些情況下會(huì)等到收到響應(yīng)(HTTP、TCP/IP、WS、REST、WebSocket)。
Camel的一個(gè)關(guān)鍵好處是,它提供了根據(jù)它所攜帶的信息(使用消息結(jié)構(gòu))做出決策的可能性。這樣一個(gè)與對(duì)象交換相對(duì)應(yīng)的消息包含了主體中攜帶的信息或?qū)ο?,但也包含了頭的元數(shù)據(jù)部分。
元數(shù)據(jù)允許您記錄傳輸?shù)膶?duì)象,但也可以知道它們來(lái)自何處、它們的來(lái)源(文件、Ftp、WebService、SMTP、JDBC、JPA、JMS等)以及它們應(yīng)該去哪里。為了支持決策,Camel使用一種EIP模式,即基于內(nèi)容的路由器、過(guò)濾器、聚合器、拆分器……以及一種稱為表達(dá)式語(yǔ)言(Simple、Constant、Xpath、Xquery、SQL、Bean、Header、Body、OGNL、Mvel、EL……)的特定語(yǔ)言。
這些決定是由謂詞做出的,我們可以將這些謂詞與If/Then/Else、While/For語(yǔ)句進(jìn)行比較。路由引擎將決定如何處理“消息”以及它們應(yīng)該去哪里。
如果滿足條件,基于內(nèi)容的路由器使用的選項(xiàng)/時(shí)間將計(jì)算(使用謂詞和表達(dá)式語(yǔ)言)。如果是這種情況,則將交換移動(dòng)到分支路徑中定義的處理器,否則它們將移動(dòng)到另一個(gè)管道中。所有這些都體現(xiàn)在以下方面:
// from("Brussels") .bean("Border","validPassport") .choice() .when() .simple(${header.isValid}==true) // Simple language checks if the status is equal to true .log("Passenger has been controlled") .log("We can now control their ticket") .bean("Border","controlTicket") .to("Paris") .otherwise() .log("Your are not authorized to continue your trip");
對(duì)于所使用的某些組件,預(yù)期接收方(HTTP、WebService、REST、JMS–Request/Reply、TCP/IP等)或發(fā)出消息的發(fā)送方會(huì)發(fā)出響應(yīng)。在這種情況下,Camel將調(diào)整用于內(nèi)部傳輸消息的模式。此模式通常為InOnly類型,但當(dāng)需要響應(yīng)時(shí),將使用InOut模式。為了傳輸信息并避免將傳入消息與傳出消息混合,Apache Camel將為此目的使用兩個(gè)不同的對(duì)象,即in或out。當(dāng)不需要響應(yīng)時(shí),即我們舉例來(lái)說(shuō),如果使用一個(gè)文件組件,那么out對(duì)象總是空的。
更進(jìn)一步
由于流量由運(yùn)營(yíng)商控制,apachecamel提供了一個(gè)管理路由的環(huán)境(啟動(dòng)/停止/暫停/恢復(fù)路由中的流量)。這種環(huán)境被稱為容器,或者更準(zhǔn)確地說(shuō)是上下文。
容器不僅是部署路由的運(yùn)行時(shí),而且充當(dāng)復(fù)雜的生態(tài)系統(tǒng)。它可以跟蹤交換,如何使用框架公開(kāi)的JMX信息進(jìn)行管理,如何處理線程池,如何發(fā)現(xiàn)路由,如何關(guān)閉路由并生成創(chuàng)建交換時(shí)使用的唯一標(biāo)識(shí)符。
CamelContext還將注冊(cè)使用或生成該信息所需的組件。根據(jù)URI中包含的方案名稱,Apache Camel將掃描classloader加載的類,以找到它想要使用的組件:
"scheme://properties?key1=val2&key2=val3 // "?le:///home/user/integration? " "timer://myTimer?delay=2s&period=10S"
Component類是一個(gè)工廠,它將根據(jù)從URI收集的參數(shù)創(chuàng)建一個(gè)Endpoint對(duì)象(?)?鍵1=值1和鍵1=值2。此對(duì)象包含根據(jù)組件扮演的角色創(chuàng)建生產(chǎn)者或使用者所需的方法。
通常,輪詢消費(fèi)者定期掃描文件系統(tǒng)的目錄,讓JMS的偵聽(tīng)器讀取JMS消息,并將創(chuàng)建一個(gè)交換,它將傳播到下一個(gè)處理器,如下所示:
@Override protected int poll() throws Exception { Exchange exchange = endpoint.createExchange(); // create a message body Date now = new Date(); exchange.getIn().setBody("Hello World! The time is " + now); try { // send message to next processor in the route getProcessor().process(exchange); return 1; // number of messages polled } }
在另一端,生產(chǎn)者將等待,直到它從處理器得到一個(gè)駝峰交換,然后將操縱“消息”,豐富它并更改“元數(shù)據(jù)”:
public void process(Exchange exchange) throws Exception { // Add a new property exchange.getIn().setHeader("FrequentFlyer","true); }
Camel項(xiàng)目通常由一個(gè)Java主類組成,我們將在其中創(chuàng)建一個(gè)DefaultCamelContext,注冊(cè)Camel路由并啟動(dòng)容器。如以下示例所述,RouteBuilder類是必需的,它的Configure方法調(diào)用靜態(tài)方法(=指令)來(lái)設(shè)計(jì)駝峰路由(=處理器集合)。路由生成器允許創(chuàng)建一到多條駝峰路由:
// public class MainApp { public static void main(String[] args) throws Exception { // CamelContext = container where we will register the routes DefaultCamelContext camelContext = new DefaultCamelContext(); // RouteBuilder = Where we design the Routes using here Java DSL RouteBuilder routeBuilder = new RouteBuilder() { @Override public void configure() throws Exception { from(?file:///travelers“) .bean(“Flight”,”TransportPassenger”) .to(?file:///authorizedTravelers“); } }; // Add the routes to the container camelContext.addRoutes(routeBuilder); // Start the container camelContext.start(); // When work is done we shutdown it camelContext.stop();
與其他集成框架相比,apachecamel是獨(dú)一無(wú)二的,因?yàn)樗軌蛱幚鞪ava對(duì)象,并且能夠自動(dòng)將對(duì)象類型轉(zhuǎn)換為處理器或謂詞所期望的類型。
在創(chuàng)建CamelContext的過(guò)程中,負(fù)責(zé)進(jìn)行類型轉(zhuǎn)換的所有類(文件到字符串、讀取器、字符串到DOM等等)都將加載到一個(gè)內(nèi)部注冊(cè)表中,Camel處理器在交換處理過(guò)程中會(huì)查詢到該注冊(cè)表。這些轉(zhuǎn)換類來(lái)自不同的jar,這是java類路徑的一部分。雖然apachecamel默認(rèn)情況下完成了這樣一個(gè)過(guò)程,但是您也可以使用特定的指令來(lái)指示應(yīng)該將哪個(gè)特定的轉(zhuǎn)換器應(yīng)用于接收的對(duì)象類型。見(jiàn)下表:
// from("?le:///travelers") // The File endpoint polls every 1s second ?les // available under "travelers" directory .convertBodyTo("String") // We convert Camel Generic File object to a String // which is required by Xpath expression language during Content Based Routing .choice() .when() .xpath("/traveler/@controlled" = 'true') // Check if condition is // matched using as expression left hand side part and condition, right hand side .log("Passenger has been controlled") .to("?le:///authorizedTravelers") .otherwise() .log("Your are not authorized to continue your trip");
下一次
在apachecamel文章的第一部分中,我們介紹了這個(gè)Java集成框架的一些基本功能,實(shí)現(xiàn)了企業(yè)集成模式,該模式使用特定于領(lǐng)域的語(yǔ)言來(lái)設(shè)計(jì)在系統(tǒng)/應(yīng)用程序之間傳輸消息的路由。
DSL允許我們定義按順序讀取的指令。當(dāng)Camel組件接收或使用信息時(shí),將創(chuàng)建一個(gè)交換,并將其移動(dòng)到一個(gè)處理器集合中,這些處理器對(duì)鏈接到Body對(duì)象的消息的內(nèi)容進(jìn)行轉(zhuǎn)換。該框架能夠使用支持的一種表達(dá)式語(yǔ)言(Xpath、Simple、SQL、Header、Body、Constant、EL、JavaScript等)和允許我們定義條件的謂詞做出決策(基于內(nèi)容的路由器、過(guò)濾器等)。在交換的傳輸過(guò)程中,Camel將使用包含轉(zhuǎn)換策略的內(nèi)部注冊(cè)表自動(dòng)將對(duì)象從和/或轉(zhuǎn)換為特定類型。Camel項(xiàng)目通常使用一個(gè)稱為CamelContext的容器來(lái)注冊(cè)Camel路由、端點(diǎn)。在本系列的第二部分中,我們將介紹Camel更高級(jí)的特性(復(fù)雜數(shù)據(jù)格式的轉(zhuǎn)換、多線程、異步交換等)。
作者介紹
熱門博客推薦