骆驼:如何从配置中有条件地构建路由?

时间:2016-04-07 18:57:23

标签: java spring apache-camel

我有一个RouteBuilder子类,用于设置我的Camel路由。它由Spring构建。最初它看起来像这样:

@Override
public void configure() throws Exception {
    from(...)
    .process(...)
    .to(...)
}

我想要做的是根据配置添加额外的端点路由。 Spring使用一个Properties文件来创建RouteBuilder bean,其中一个字段是boolean addAnotherEndpoint。如果此布尔值为true,我想添加另一个to。如果它是假的,我希望它回归到它当前的行为。所以我改成了这个:

@Override
public void configure() throws Exception {
    from(...)
    .process(...)
    .to(...)
    .choice()
        when(constant(addAnotherEndpoint)).to(...)
    .endChoice();
}

虽然这似乎有所期望的行为,但我遇到了为它编写单元测试的问题(因为它从属性文件中提取了addAnotherEndpoint的值,即使我是试图在我的测试中覆盖它)。有没有更好的方法来处理这个?我目前的方法会有任何意想不到的副作用吗?

修改

我正在使用CamelSpringTestSupport子类进行测试(使用JUnit测试)。在@Before方法中,我创建了一个AdviceWithRouteBuilder,用模拟替换所有端点。在我的@Test中,我试图覆盖从属性文件中获取的addAnotherEndpoint的值:

@Test
public void testConditionalRouting() throws Exception {
    context.start();
    MyRouteBuilder routeBuilder = (MyRouteBuilder) applicationContext.getBean("myRouteBuilder");
    routeBuilder.setAddAnotherEndpoint(true);
    getMockEndpoint("myMockEndpoint").expectedMessageCount(1);
    sendMockMessage();
    assertMockEndpointsSatisfied();
    context.stop();
}

有一个相应的测试将addAnotherEndpoint设置为false并断言收到了0条消息。问题是覆盖这个变量的值似乎并没有起作用。一个测试通过,另一个测试失败,具体取决于我的属性文件是否表示值应为truefalse。这对我来说是在我覆盖设置之前构建路径(因此也是在上下文启动之前)。我检查了调试器并正确覆盖了 设置。它似乎没有任何影响。

编辑2:

来自我的AdviceWithRouteBuilder

@Override
public void configure() throws Exception {
    replaceFromWith(MOCK_FROM_ENDPOINT);
    interceptSendToEndpoint(FIRST_TO_ENDPOINT)
            .skipSendToOriginalEndpoint().to(MOCK_FIRST_TO_ENDPOINT);
    weaveById(MY_PROCESSOR_ENDPOINT).replace()
            .to(MOCK_MY_PROCESSOR_ENDPOINT);
    weaveById(SECOND_TO_ENDPOINT).replace()
            .to(MOCK_SECOND_TO_ENDPOINT);
}

这将用模拟端点替换每个EIP。我有4个依赖于这些的测试,它们似乎按预期工作,唯一的问题是条件路由。

除了JUnit注释之外,我的测试类上唯一的注释是@Override isUseAdviceWith()(返回true)和createApplicationContext(),它返回一个新的Spring Application Context。

我在没有context.start()的情况下运行我的测试,并且唯一通过的是接收断言0消息的测试(如果路由未启动则有意义)。所以我不相信上下文是自动启动的。

2 个答案:

答案 0 :(得分:1)

以下是最终工作的内容:

我的测试很好,但我不得不重新考虑如何构建自己的路线。发生了什么是在创建Spring上下文时,正在构建路由。它检查了当时addAnotherEndpoint的值,并根据该值设置了constant。但是boolean是一个原始值,这意味着它是按值传递的。为什么这很重要?因为constant()函数只是根据构建路径时的常量的值来设置路径。稍后通过Spring更改它没有任何影响因为已经读取了该值。我需要做的是让它将一个对象作为谓词传递,这样我以后就可以像bean一样操纵同一个对象了。

此外,我按照建议从choice()更改为filter()。这是成品:

@Override
public void configure() throws Exception {
    from(...)
    .process(...)
    .to(...)
    .choice()
        when(myBooleanPredicate).to(...)
    .endChoice();
}

我的自定义谓词可以通过Spring操作:

public class BooleanPredicate implements Predicate {
  private boolean value;

  @Override
  public boolean matches(Exchange exchange) {
    return value;
  }

  public void setValue(boolean value) {
    this.value = value;
  }

BooleanPredicate的内部value设置为addAnotherPredicate。每次路由运行时都会重新读取,因为BooleanPredicate是通过引用传递的。

答案 1 :(得分:0)

我刚刚发现

.when(exchange-> foo()==true)

足够了。