【问题标题】:Camel: How to build a route conditionally from configuration?Camel:如何根据配置有条件地构建路线?
【发布时间】:2019-07-19 19:22:45
【问题描述】:

我有一个RouteBuilder 子类来设置我的骆驼路线。它是由 Spring 构建的。最初它看起来像这样:

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

我想做的是根据配置添加一个额外的端点路由。 Spring 使用一个属性文件来创建RouteBuilder bean,它设置的字段之一是boolean addAnotherEndpoint。如果这个布尔值是真的,我想添加另一个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。这对我的建议是,在我覆盖设置之前(因此也在上下文开始之前)正在构建路线。我签入了一个调试器,设置 is 被正确覆盖。它似乎没有任何影响。

编辑 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 on isUseAdviceWith()(返回 true)和 createApplicationContext(),它返回一个新的 Spring Application Context。

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

【问题讨论】:

  • 这对我来说似乎是一条非常正常的路线。我想唯一的问题是你测试它的方式。在现场环境中,这条路线应该没问题。你能分享一下你是如何测试它的吗?然后我们也可以解决这个问题。顺便说一句,如果您使用过滤器,而不是只有一个条件的选择,它会更简单。
  • 感谢您的建议。我正在使用CamelSpringTestSupport 子类对其进行测试。我将更新问题以包含此内容。
  • 我也可以看看你的 AdviceWithRouteBuilder 块吗?另外,您的测试类是否有任何注释?你也可以删除 context.start();从测试开始,然后运行它们以查看上下文是否自动启动?如果是这样,问题就在那里......
  • 再次更新问题。
  • 你在那里做了很好的分析。如果不是我,我相信其他人将能够帮助你。就在您的选择之前,如果您记录 addAnotherEndpoint,您会看到什么?由于这对我来说是唯一未解决的问题,您能否分享一下您是如何覆盖此属性的?

标签: java spring apache-camel


【解决方案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 是通过引用传递的,因此每次运行路由时都会重新读取它。

【讨论】:

    【解决方案2】:

    我刚刚发现

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

    足够了。

    【讨论】:

      猜你喜欢
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      • 2013-04-21
      • 1970-01-01
      • 1970-01-01
      • 2022-11-30
      • 1970-01-01
      • 2020-09-04
      相关资源
      最近更新 更多