Java运行时添加Camel路由


Apache Camel是一个 Java 框架,可以轻松实现各种企业集成模式 (EIP),从而为企业集成提供解决方案。

集成模式中的常见任务之一是根据特定规则和条件确定运行时的消息路由。Apache Camel 通过提供一种实现动态路由器 EIP 的方法来简化此过程。

在本教程中,我们将深入研究如何在 Apache Camel 中实现动态路由的详细信息,并通过一个示例进行演练。


什么是动态路由器
有时,我们希望在运行时根据特定的规则和条件将消息发送到不同的路由。Routing Slip EIP 等解决方案可以帮助解决问题,但效率较低,因为它需要反复试验。

在路由表 EIP 中,消息包含要按定义的顺序路由到的端点列表。这需要预先配置端点列表并使用试错方法通过每个端点发送消息。
动态路由器 EIP 提供了更好的实现来在运行时添加路由,特别是在我们有多个收件人或根本没有收件人的情况下。它提供了路由消息的灵活性,无需预先配置严格的端点。

此外,它还知道每个目的地以及将消息路由到特定目的地的规则。此外,它还有一个控制通道,潜在目的地可以通过在启动时宣布其存在和参与规则来与其进行通信。

此外,它将所有可能目的地的规则存储在规则库中。消息到达后,它会检查规则库并满足收件人的请求。

此外,一个常见的用例是动态服务发现,其中客户端应用程序可以通过发送包含服务名称的消息来访问服务。

动态路由器 EIP 的核心目标是将路由决策推迟到运行时,而不是预先构建静态规则。

Maven依赖
让我们通过将camel-core和camel-test-junit5添加到pom.xml来引导一个简单的Apache Camel项目:

<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-core</artifactId>
    <version>4.3.0</version>
</dependency>
<dependency>
    <groupId>org.apache.camel</groupId>
    <artifactId>camel-test-junit5</artifactId>
    <version>4.3.0</version>
</dependency>

Camel Core 提供动态路由器 EIP 以及其他路由功能,Camel Test JUnit5 通过CamelSupport接口帮助更轻松地测试消息路由。

值得注意的是,我们还可以将 Camel 项目引导为Spring Boot项目。

使用动态路由器在运行时添加路由
动态路由器 EIP 确保我们为集成系统指定规则,以帮助在运行时正确匹配特定路由。它检查传入消息的正文并将其与路由进行匹配。

配置
首先,我们创建一个名为DynamicRouteBean的类并添加一个方法来定义规则和条件:

class DynamicRouterBean {
    public String route(String body, @ExchangeProperties Map<String, Object> properties) {
        int invoked = (int) properties.getOrDefault("invoked", 0) + 1;
        properties.put(
"invoked", invoked);
        if (invoked == 1) {
            switch (body.toLowerCase()) {
                case
"mock":
                    return
"mock:dynamicRouter";
                case
"direct":
                    return
"mock:directDynamicRouter";
                case
"seda":
                    return
"mock:sedaDynamicRouter";
                case
"file":
                    return
"mock:fileDynamicRouter";
                default:
                    break;
            }
        }
        return null;
    }
}

在上面的代码中,我们根据传入的消息正文和当前调用计数动态确定适当的路由。Route () 方法检查消息正文是否符合任何预定义的关键字规则并返回相应的路由。

此外,我们在Map对象上使用@ExchangeProperties 注释。该映射用作存储和检索交换的当前状态并更新调用计数的容器。

此外,invoked变量表示调用route() 方法的次数。如果消息符合预定义条件并且是第一次调用,则返回相应的路由。invoked == 1检查有助于在第一次调用时执行动态路由逻辑。这简化了这种特定情况下的代码并防止不必要的重新执行。

另外,为了防止动态路由器无休止地执行,route()方法在路由到适当的端点后返回null 。这确保了动态路由在基于消息识别出路由后结束。

简单地说,每次交换都会调用route()方法,直到返回null 。

最后,让我们在 Camel 路由构建器中配置动态路由器 EIP:

class DynamicRouterRoute extends RouteBuilder {
    @Override
    void configure() {
        from("direct:dynamicRouter")
          .dynamicRouter(method(DynamicRouterBean.class,
"route"));
    }
}

在上面的代码中,我们创建了扩展 RouteBuilder 的DynamicRouterRoute类。 接下来,我们重写configure方法并通过调用dyamicRouter ()方法添加动态路由bean,以将动态路由器调用连接到我们的自定义route()。

值得注意的是,我们可以在定义规则的方法上使用@DynamicRouter 注释:

class DynamicRouterBean {
    @DynamicRouter
    String route(String body, @ExchangeProperties Map<String, Object> properties) {
        // ...
    }
}

该注释消除了在Camel路由中显式配置dynamicRouter()方法的需要:

// ...
@Override
void configure() {
    from(
"direct:dynamicRouter").bean(DynamicRouterBean.class, "route");
}  
// ...

在上面的代码中,我们使用bean() 方法指定包含路由逻辑的类。不再需要dynamicRouter()方法,因为route ( )方法用@DynamicRouter注释。

单元测试
让我们编写一个单元测试来断言某些条件是否为真。首先,让我们确保我们的测试类扩展CamelTestSupport:

class DynamicRouterRouteUnitTest extends CamelTestSupport {
    @Override
    protected RoutesBuilder createRouteBuilder() {
        return new DynamicRouterRoute();
    } 
}

在这里,提供一个DynamicRouterRoute实例,用作测试的路由构建器。

接下来,让我们看看名为mock的传入消息正文:

@Test
void whenMockEndpointExpectedMessageCountOneAndMockAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException {
    MockEndpoint mockDynamicEndpoint = getMockEndpoint("mock:dynamicRouter");
    mockDynamicEndpoint.expectedMessageCount(1);
    template.send(
"direct:dynamicRouter", exchange -> exchange.getIn().setBody("mock"));
    MockEndpoint.assertIsSatisfied(context);
}

在这里,我们模拟动态端点并将预期的消息路由设置为其值。接下来,我们将预期消息计数设置为 1。最后,我们使用预期的正文消息设置传入消息路由,并断言MockEndpoint路由已满足。

另外,让我们模拟“ mock:directDynamicRouter ”消息路由:

@Test
void whenMockEndpointExpectedMessageCountOneAndDirectAsMessageBody_thenMessageSentToDynamicRouter() throws InterruptedException {
    MockEndpoint mockDynamicEndpoint = context.getEndpoint("mock:directDynamicRouter", MockEndpoint.class);
    mockDynamicEndpoint.expectedMessageCount(1);
    template.send(
"direct:dynamicRouter", exchange -> exchange.getIn().setBody("direct"));
    MockEndpoint.assertIsSatisfied(context);
}

此测试验证当“ direct ”作为消息正文发送时,它会动态路由到“ mock:directDynamicRouter ”端点。此外,我们将预期消息计数设置为 1,表示端点应接收的消息交换数。

结论
在本文中,我们学习了如何使用动态路由器 EIP 在 Apache Camel 中运行时添加路由。与使用试错方法将消息发送到路由的路由滑动不同,动态路由器 EIP 提供了可靠的实现来根据特定规则和条件路由到端点。