1. 概述
Apache Camel 是一個強大的開源集成框架,實現了多種已知的企業集成模式。
通常在使用 Camel 進行消息路由時,我們需要根據消息內容以不同的方式處理消息。為此,Camel 提供了一個強大的功能,稱為 基於內容路由器,來自 企業集成模式 集合。
在本教程中,我們將探討多種基於條件的消息路由方法。
2. 依賴項
為了開始,我們只需要將 camel-spring-boot-starter 添加到我們的 pom.xml 中:<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>然後,我們需要將 <em><a href="https://mvnrepository.com/artifact/org.apache.camel/camel-test-spring-junit5">camel-test-spring-junit5</a></em> 依賴添加到我們的 <em>pom.xml</em> 中:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring-junit5</artifactId>
<version>4.3.0</version>
</dependency>正如其名稱所示,這個依賴項專門用於我們的單元測試。
3. 定義一個簡單的 Camel Spring Boot 應用
在整個教程中,我們示例的重點將是簡單的 Camel Spring Boot 應用。
讓我們首先定義應用程序的入口點:
@SpringBootApplication
public class ConditionalRoutingSpringApplication {
public static void main(String[] args) {
SpringApplication.run(ConditionalRoutingSpringApplication.class, args);
}
}如我們所見,這是一個標準的 Spring Boot 應用。
4. 條件路由
為了快速回顧,Apache Camel 中的 路由 是一個基本構建塊,通常由 Camel 執行的順序步驟組成,用於消費和處理消息。
例如,路由通常會接收一條消息,使用例如從磁盤上的文件或消息隊列的消費者。然後,Camel 執行路由中的其餘步驟,無論是否處理消息,或者將其發送到其他端點。
毫無疑問,我們想要一種基於某些事實來條件路由消息的方式。為此,Camel 提供了 choice 和 when 構造。我們可以將其視為 Java 中 if-else 語句的等效項。
考慮到這一點,讓我們創建一個帶有條件邏輯的第一個路由。
5. 創建路由
在示例中,我們將定義一個基本的路由,並根據消息主體的內容包含一些條件邏輯:
@Component
public class ConditionalBodyRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:start-conditional")
.routeId("conditional-body-route")
.choice()
.when(body().contains("Baeldung"))
.setBody(simple("Goodbye, Baeldung!"))
.to("mock:result-body")
.otherwise()
.to("mock:result-body")
.end();
}
}如我們所見,在我們的簡單示例中,我們配置路由以從一個 直接端點 start-conditional 中消費消息。
現在,讓我們逐步瞭解路由的關鍵部分:
- 首先,我們使用 choice() 方法開始路由 – 這告訴 Camel 後面的行將包含一些條件進行評估
- 接下來,when() 方法指示一個新的條件進行評估 – 在本例中,我們簡單地檢查消息主體是否包含字符串 Baeldung。我們可以添加任意數量的 when 條件
- 為了總結路由,我們使用 otherwise() 方法定義在沒有滿足任何先前 when 條件的情況下該執行的操作。
- 最後,路由使用 end() 方法終止,該方法關閉 choice 塊。
總而言之,當運行我們的路由時,如果消息主體包含字符串 Baeldung,我們將消息主體設置為 Goodbye, Baeldung! 並將結果發送到名為 result-body 的 模擬端點。
或者,我們只需將原始消息路由到我們的模擬端點。
6. 測試路由
考慮到上一部分內容,我們現在來編寫一個單元測試,以探索我們的路由行為:
@SpringBootTest
@CamelSpringBootTest
class ConditionalBodyRouterUnitTest {
@Autowired
private ProducerTemplate template;
@EndpointInject("mock:result-body")
private MockEndpoint mock;
@Test
void whenSendBodyWithBaeldung_thenGoodbyeMessageReceivedSuccessfully() throws InterruptedException {
mock.expectedBodiesReceived("Goodbye, Baeldung!");
template.sendBody("direct:start-conditional", "Hello Baeldung Readers!");
mock.assertIsSatisfied();
}
}如我們所見,我們的測試包含三個簡單的步驟:
- 首先,讓我們設置一個期望,即我們的模擬端點將接收給定的消息主體
- 然後,我們將使用我們的模板向我們的 direct:start-conditional 端點發送一條消息。請注意,我們將確保我們的消息主體包含字符串 Baeldung
- 為了總結我們的測試,我們使用 assertIsSatisfied 方法來驗證我們在模擬端點上的初始期望是否已滿足
此測試確認我們的條件路由正在正確運行。太棒了!
請務必查看我們的以前教程,以瞭解如何為我們的 Camel 路由編寫可靠且自包含的單元測試。
7. 構建其他條件謂詞
到目前為止,我們已經探討了構建我們的 謂詞的一種方法,即檢查交換消息的主體。但是,還有其他幾種選項可供我們使用。
例如,我們可以通過檢查給定消息頭的值來控制我們的條件:
@Component
public class ConditionalHeaderRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:start-conditional-header")
.routeId("conditional-header-route")
.choice()
.when(header("fruit").isEqualTo("Apple"))
.setHeader("favourite", simple("Apples"))
.to("mock:result")
.otherwise()
.setHeader("favourite", header("fruit"))
.to("mock:result")
.end();
}
}本次,我們修改了 when 方法,使其能夠查看名為 fruit 的 header 的值。 此外,還可以使用 Camel 提供的 Simple language 在 when 條件中使用。
8. 使用 Java Bean
此外,我們還可以使用 Camel Bean 語言,以便在我們的謂詞中利用 Java 方法調用的結果。
首先,我們需要創建一個包含返回布爾值的 Java Bean:
public class FruitBean {
public static boolean isApple(Exchange exchange) {
return "Apple".equals(exchange.getIn().getHeader("fruit"));
}
}我們還可以選擇將 Exchange 作為參數傳遞,以便 Camel 會自動將 Exchange 傳遞到我們的方法中。
然後我們可以使用來自 when 塊的 FruitBean:
@Component
public class ConditionalBeanRouter extends RouteBuilder {
@Override
public void configure() throws Exception {
from("direct:start-conditional-bean")
.routeId("conditional-bean-route")
.choice()
.when(method(FruitBean.class, "isApple"))
.setHeader("favourite", simple("Apples"))
.to("mock:result")
.otherwise()
.setHeader("favourite", header("fruit"))
.to("mock:result")
.endChoice()
.end();
}
}9. 結論
在本文中,我們學習瞭如何在路由中根據條件進行消息路由。首先,我們創建了一個簡單的 Camel 應用,其中包含一個路由,用於檢查消息體。
然後,我們學習了使用消息頭和 Java Bean 等技術構建路由中的謂詞(predicate)的各種方法。