Apache Camel 中的 SEDA、Direct、Direct-VM 和 VM 組件、它們的作用以及何時可以使用它們。帶有代碼示例。

在設計 Camel 路線時,您有時可能希望路線具有多個輸入。也許你想從Web服務接收消息和從
你不能在同一個路由中有多個from()方法,那么你怎么能在同一個路由中有多個入口點呢?
同樣,您可能希望在多個地方重用相同的 Camel 消息處理邏輯,那么如何避免重復代碼呢?
這兩個問題的答案是使用 Camel 的內存中消息傳遞組件將您的路由連接在一起:Direct、Direct-VM、VM 和 SEDA。
在本文中,我將解釋這些組件中的每一個,它們有何不同,以及如何使用它們使您的路由更加模塊化和更棒。
首先……一個示例場景
首先,我將從一個例子開始。
我定義了一個路由,通過將消息傳遞給某個底層系統來驗證傳入的訂單。我的訂單最初是通過 JMS 消息到達的。

但是,當訂單開始來自新來源(例如文件上傳或 Web 服務調用)時會發生什么?
為了避免重復相同的路由代碼,Camel 具有內置功能,允許路由具有多個輸入,通過使用一系列連接組件將這些路由粘合在一起。
那么它是怎樣工作的?Camel 使用組件 Direct、VM 和 SEDA 將端點粘合在一起。
這些組件以不同的方式將您的 Camel 路線連接在一起。它們統稱為 Camel 的內存中消息組件,因為它們允許消息在路由之間傳遞,而消息始終保留在內存中。這是一個非常重要的細節,我稍后會再次提及。
但是現在,讓我們看看這些組件中的每一個,看看它們有什么不同,以及您可以在哪里使用它們。
Direct component
這一定是 Camel 初學者最常問到的問題之一:
路徑中的“direct”是什么意思?

您可能已經在網絡上的許多 Camel 教程中看到過這些代碼direct:...。但direct實際上有什么作用呢?
Apache Camel 的
direct是將您的路線鏈接在一起的最簡單的方法之一。當它在from()定義中使用時,它會創建一個可以被其他 Camel 路由調用的同步端點。例如,這段以from(direct)開頭的代碼:
from("direct:yourname")...
...將創建一個名為yourname. 這同一個端點然后可以在另一個被調用to()語句別的地方,就像這樣:
.to("direct:yourname"); // sends the message to the direct:yourname endpoint
在示例中,它經常被使用,因為它提供了一個簡單的路由入口點,而不必公開 Web 服務,或以其他方式依賴外部接口。
示例:使用 Direct 組件
讓我們用一個例子來說明 Direct 組件:
from("file:/home/files/in") // receive a file
.to("direct:processTheFile"); // send to direct endpoint
.to("Body is now ${body}"); // will print 'Eggs!'
// meanwhile...
from("direct:processTheFile") // receive from direct endpoint
.setBody("Eggs!"); // modify the message body</code>
但是,Direct 的簡單性也有一些缺點。
直接端點只能被在同一個 CamelContext和同一個 JVM中運行的其他路由訪問。這意味着您不能從另一個 CamelContext 訪問 Direct 端點。請記住,CamelContext 是創建和啟動 Camel 路由的容器。
那么如果你想訪問另一個 CamelContext 中的路由會發生什么?您使用下一個組件 Direct-VM。
這個非常簡單的示例使用 Camel 的 File 組件接收文件。處理的每個文件都作為 Exchange 傳遞到直接端點processTheFile。
另外,我們已將processTheFile端點定義為修改消息正文的路由的起始組件。完成此操作后,新消息將返回到調用路由。所有這些都是在同一個線程中同步發生的。
Direct-VM component
Direct-VM 是一個組件,它允許您同步調用同一 JVM 中的另一個端點,即使它位於不同的CamelContext 中。
當用作啟動組件時,Direct-VM 將該路由公開為可以從另一個路由同步調用的端點。
與
示例:使用 Direct-VM 組件
如果我們想炫耀 Direct-VM 組件,我們可以在應用程序 A 中定義一個路由:
java from("file:src/files/input") .to("direct-vm:process-file") // invoke the direct-vm endpoint
這將調用此 Direct 端點,位於應用程序 B 中...:
java from("direct-vm:process-file") // receive from direct-vm endpoint .to("log:samplelog"); // log the message
只要這兩個應用程序都在同一個 JVM 中運行——例如,在同一個 Spring Boot 應用程序中使用一個應用程序容器,如 Apache Karaf、Wildfly 甚至不同的 CamelContexts——那么應用程序 A 將能夠調用direct-vm應用程序中的端點B.
這開辟了將不在同一 CamelContext 中開發的路由鏈接在一起的可能性。例如,如果您在一個容器中部署了不同的 CamelContexts,您可能會使用此組件 - 例如當您
SEDA組件
Camel 的 SEDA 組件允許您使用簡單的queue將路由連接在一起。
在 Camel 路由中,當消息被發送到 SEDA 端點時,它被存儲在一個基本的內存隊列中,並且控制立即返回到調用路由。
然后,SEDA 使用者獨立地從隊列中提取消息,並開始處理它。
示例:使用 SEDA 組件
下面是一個 SEDA 隊列的例子:
java rest("/orders").post() // receive an order via REST .to("seda:processOrder"); // send to the seda queue .setBody("Thanks for ordering!"); // create a REST response
from(“seda:processOrder”) // 從 seda 隊列接收 .log(“Processing an order…”) .to(“file:orders/out”);</code>
在上面的示例中,消息將通過 REST 服務接收並發布到 SEDA 端點。消息到達processOrderSEDA 端點並進行處理,然后使用該file:組件將它們寫入磁盤上的某個位置。
SEDA 通過創建自己的緩沖區來實現這一點,該緩沖區用於存儲傳入的消息。SEDA 開箱即用地創建了一個線程池來處理傳入的消息,這意味着可以一次處理多條消息,從而使其可能具有更高的性能。
通過這種方式,可以將 SEDA 視為 JMS 隊列的簡單替代品。它提供了類似隊列的功能,但沒有運行像 ActiveMQ 這樣的外部消息代理的開銷。
請記住,Camel 將消息異步發布到 SEDA 端點。
您只能訪問位於同一 CamelContext 中的SEDA 端點。那么如果你想向另一個 CamelContext 中的 SEDA 隊列發送消息會發生什么?您使用下一個組件 VM。
VM component
與 Direct 和 Direct-VM 的關聯方式類似,VM 是與 SEDA 類似的組件。
當用作啟動組件時,SEDA 允許從另一個路由異步調用一個路由。
然而,SEDA 和 VM 之間的區別在於
同樣,VM 組件開啟了以異步方式將不在同一 Camel 上下文中開發的路由鏈接在一起的可能性。
SEDA 和 VM 的缺點
使用像 SEDA 和 VM 這樣的內存消息傳遞的最大缺點是,如果應用程序崩潰,您很有可能會丟失所有消息。
如果您設計的集成類型與消息丟失無關緊要,那么這不是主要考慮因素。
但是回想一下本文頂部的訂單處理示例。如果訂單在服務器中斷期間丟失,這可能意味着失去業務。(呃哦。)
考慮一下何時適合使用這些內存中的消息傳遞組件,以及何時將消息移交給外部消息代理(例如
沒有硬性規定。正確的解決方案始終取決於您的用例。因此,在使用 Camel 設計集成時,請考慮丟失消息時該怎么辦。會有關系嗎?如果是這樣,請考慮使用事務和持久消息傳遞來最大程度地減少任何消息丟失。
總結和最佳實踐
所以現在您已經了解了每個組件,您應該使用哪個,以及何時使用?
SEDA 與 Direct
-
對於同一 CamelContext 中的同步(請求/響應)交互,請使用Direct
-
對於同一 CamelContext 中的異步(即發即忘)處理(以類似隊列的方式處理消息),請使用SEDA
VM 與 Direct-VM:
-
對於不同 CamelContext但在同一個 JVM 中的**同步(請求/響應)交互,使用Direct-VM**
-
對於不同 CamelContext但在同一 JVM 中的**異步(即發即忘)交互,請使用VM**
Direct、SEDA、VM 和 Direct-VM 的比較
此表比較了每個組件,並顯示它們是否可以從另一個 CamelContext(在同一 JVM 中)訪問:
| Component | 類型 | 來自同一個 CamelContext | 來自另一個 CamelContext |
|---|---|---|---|
| Direct | 同步 | 是的 | 不 |
| Direct-VM | 同步 | 是的 | 是的 |
| SEDA | 異步 | 是的 | 不 |
| VM | 異步 | 是的 |
