NotifyBuilder
NotifyBuilder
NotifyBuilder 是 org.apache.camel.builder 包中的一个构建器,它允许你构建表达式,然后测试或等待某个条件的发生。这些表达式围绕着 Exchange 被路由的通知构建。这是什么意思呢?
它的意思是,你可以构建一个表达式,用来告诉你 Camel 何时完成了对 5 条消息的路由等操作。当你测试一条既不能也不打算使用 Mock 组件的路由时,可能会用到它。
NotifyBuilder 仅用于测试目的,且只能通过 Java 代码使用。 |
|---|
使用 NotifyBuilder 的基本示例
假设我们有一条非常简单的路由:
仅限 Java:用于演示 NotifyBuilder 的简单路由
from("jms:queue:quotes")
.to("bean:quotes");想象一下这条路由更复杂,是一条生产就绪的路由。
现在你想要测试这条路由,而不使用 mock 或类似的工具。我们想要测试它是否能够处理发送到该队列的消息。通过使用 NotifyBuilder,我们可以构建一个表达式,用来表示该条件何时发生。
仅限 Java:基本的 NotifyBuilder 等待一条消息完成
NotifyBuilder notify = new NotifyBuilder().whenDone(1).create();
// now use some API to send a message etc. Maybe you cannot use Camel's ProducerTemplate
// now we want to wait until the message has been routed and completed
boolean done = notify.matches(10, TimeUnit.SECONDS);
assertTrue("Should be done", done);
// now maybe use some API to see that the message did as expected这是一个非常基础的示例,我们在其中配置了 NotifyBuilder,使其在任意 Exchange 完成时进行匹配。
该构建器还提供了许多其他方法,可以设置更复杂的表达式,甚至可以使用 and、or、not 运算进行叠加组合。
NotifyBuilder API
NotifyBuilder 提供了许多方法,可以用来构建更加复杂的表达式。下表列出了最常用的方法。
| 方法 | 描述 |
|---|---|
from(endpointUri) | 仅当 Exchange 从该特定端点进入时匹配。endpointUri 可以是一个模式,其模式匹配方式与 Intercept 所使用的相同。 |
fromRoute(routeId) | 仅当 Exchange 从该特定路由进入时匹配。routeId 可以是一个模式,其模式匹配方式与 Intercept 所使用的相同。 |
filter(predicate) | 过滤掉不需要的 Exchange(仅使用通过(返回 true)该谓词的消息)。 |
wereSentTo(endpointUri) | 仅当 Exchange 在某一时刻曾被发送到给定端点时匹配。endpointUri 可以是一个模式,其模式匹配方式与 Intercept 所使用的相同。 |
whenDone(number) | 当有 X 条或更多消息完成时匹配。 |
whenComplete(number) | 当有 X 条或更多消息完成(complete)时匹配。 |
whenFailed(number) | 当有 X 条或更多消息失败时匹配。 |
whenBodiesDone(bodies) | 当消息体按相同顺序完成时匹配。此方法是非严格的,这意味着它会忽略任何额外的已完成消息。 |
whenAnyDoneMatches(predicate) | 若任一已完成消息匹配该谓词则匹配。 |
create | 创建通知器。创建之后即可使用 matches 相关方法。 |
matches | 测试通知器当前是否匹配。此操作会立即返回。该方法应在创建表达式之后使用。 |
matches(timeout) | 等待直到通知器匹配或超时。若匹配则返回 true,若发生超时则返回 false。此操作会立即返回。该方法应在创建表达式之后使用。 |
matchesWaitTime | 等待直到构建器匹配或超时。所使用的超时值基于所使用的任一 mock 端点上配置的最大结果等待时间。如果没有使用 mock 端点,则默认超时值为 10 秒。在单元测试中使用 mock 时,此方法非常方便,无需显式指定超时值。 |
NotifyBuilder 拥有超过 30 个方法。如需查看完整的方法列表,请参阅 NotifyBuilder 的 javadoc。
如果你想针对不同的条件接收通知,可以创建多个 NotifyBuilder 实例。NotifyBuilder 还支持使用二元运算符(and、or、not)将多个条件叠加组合。 |
|---|
done、completed 和 failed 的区别
NotifyBuilder 定义了消息完成的三种方式:
- Done — 消息处理完成,无论它是成功完成还是失败。
- Completed — 消息成功完成(没有失败)。
- Failed — 消息失败(例如抛出了异常且未被处理)。
这三种方式的名称也体现在了构建器方法的命名中:whenDone、whenCompleted 和 whenFailed。
示例
纯 Java 方式:当来自特定端点的 5 条消息全部完成时进行匹配
NotifyBuilder notify = new NotifyBuilder(context)
.from("direct:foo").whenDone(5)
.create();这里我们想要匹配 direct:foo 端点已完成 5 条消息的时刻。
你可能还希望在某条消息完成时根据索引收到通知,例如第一条消息。为此,只需这样做即可:
纯 Java 实现:使用索引匹配第一条消息完成的情况
NotifyBuilder notify = new NotifyBuilder(context)
.whenDoneByIndex(0)
.create();这可以确保通知器仅在第一条消息处理完成时才会匹配。
如果改用 whenDone(1),那么只要有至少一条消息完成,通知器就会匹配。在这种情况下,即使第一条消息尚未完成,whenDone(1) 也可能匹配,因为夹在中间的其他消息可能先于第一条消息完成。这就是引入 whenDoneByIndex 来支持该场景的原因。
这里我们希望在 direct:foo 端点完成 5 条消息、且这些消息的正文中包含 "test" 一词时进行匹配。该过滤器接受一个 Predicate。
仅 Java:在匹配之前使用谓词过滤消息
NotifyBuilder notify = new NotifyBuilder(context)
.from("direct:foo").filter(body().contains("test")).whenDone(5)
.create();在这里我们只需要说明,从任意 JMS 端点至少接收到一条消息即可(注意通配符匹配)。
仅 Java 实现:使用通配符匹配来自任意 JMS 端点的消息
NotifyBuilder notify = new NotifyBuilder(context)
.from("jms:*").whenDone(1)
.create();在这里,我们只是说明:至少有三条消息已从 myCoolRoutes 中的任意路由接收完毕(注意通配符匹配)。
仅限 Java:使用通配符匹配来自路由的消息
NotifyBuilder notify = new NotifyBuilder(context)
.fromRoute("myCoolRoutes*").whenDone(3)
.create();这里 5 条 foo 消息和 7 条 bar 消息都必须完成。注意 and 运算符的使用。
仅限 Java:使用 and 运算符合并条件
NotifyBuilder notify = new NotifyBuilder(context)
.from("direct:foo").whenDone(5)
.and().from("direct:bar").whenDone(7)
.create();这里我们期望接收两条消息,其消息体分别是 Hello World 和 Bye World。
仅 Java:匹配期望的消息体
NotifyBuilder notify = new NotifyBuilder(context)
.from("direct:foo").whenBodiesReceived("Hello World", "Bye World")
.create();这里我们期望接收到一条正文中包含 Camel 的消息。
仅限 Java:使用谓词匹配任意接收到的消息
NotifyBuilder notify = new NotifyBuilder(context)
.whenAnyReceivedMatches(body().contains("Camel"))
.create();使用 Mock 端点进行细粒度断言
仅限 Java:将 Mock 端点与 NotifyBuilder 结合使用
// let's use a mock to set the expressions as it got many great assertions for that
// notice we use mock:assert which does NOT exist in the route, it's just a pseudo name
MockEndpoint mock = getMockEndpoint("mock:assert");
mock.expectedBodiesReceivedInAnyOrder("Hello World", "Bye World", "Hi World");
NotifyBuilder notify = new NotifyBuilder(context)
.from("direct:foo").whenReceivedSatisfied(mock)
.create();这里我们将 Mock 与 NotifyBuilder 结合使用。我们使用 mock 来设置细粒度的期望,例如按任意顺序接收到 3 条消息。然后使用构建器可以指明这些消息应当来自 direct:foo 端点。你可以根据需要组合多个表达式。不过,我们建议对于你可能已经熟悉的细粒度期望使用 mock。你还可以指定 Exchange 必须已被发送到某个给定端点。
使用 wereSentTo
例如,在下面的例子中,我们期望消息被发送到 mock:bar
仅限 Java:匹配那些被发送到特定端点的消息
NotifyBuilder notify = new NotifyBuilder(context)
.wereSentTo("mock:bar")
.create();你可以将此与其他任意期望条件组合使用,例如:仅当有 3 条或更多消息处理完成且被发送到 mock:bar 端点时才匹配。
仅使用 Java:将 whenDone 与 wereSentTo 组合
NotifyBuilder notify = new NotifyBuilder(context)
.whenDone(3).wereSentTo("mock:bar")
.create();你可以添加额外的 wereSentTo 条件,例如下面这两个:
仅限 Java:链式组合多个 wereSentTo 条件
NotifyBuilder notify = new NotifyBuilder(context)
.wereSentTo("activemq:queue:foo").wereSentTo("activemq:queue:bar")
.create();同样,你还可以预期有若干消息处理完成,以及一条消息处理失败并需要被发送到另一个端点:
仅限 Java:在不同端点上组合 done 与 failed 条件
NotifyBuilder notify = new NotifyBuilder(context)
.whenDone(3).wereSentTo("activemq:queue:goodOrder")
.and().whenFailed(1).wereSentTo("activemq:queue:badOrder")
.create();评论
登录后参与评论
KnowForge