简体   繁体   English

Spring Integration DSL-JdbcPollingChannelAdapter结果未排队

[英]Spring Integration DSL - JdbcPollingChannelAdapter results not queueing

I swear I had this working, but when I can back to it after a few months (and an upgrade to Boot 1.5.9), I am having issues. 我发誓我已经完成了这项工作,但是几个月后又恢复了(并升级到Boot 1.5.9),我遇到了问题。

I set up a JdbcPollingChannelAdapter that I can do a receive() on just fine, but when I put the adapter in a flow that does nothing more than queue the result of the adapter, running .receive on the queue always returns a null (I can see in the console log that the adapter's SQL getting executed, though). 我设置了一个JdbcPollingChannelAdapter,可以很好地执行receive(),但是当我将适配器放入一个只对适配器的结果排队的流中时,在队列上运行.receive总是返回null(我可以在控制台日志中看到适配器的SQL正在执行)。

Tests below. 测试如下。 Why can I get results from the adapter, but not queue the results? 为什么我可以从适配器获得结果,但不能将结果排队? Thank you in advance for any assistance. 预先感谢您的协助。

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
@JdbcTest
public class JdbcpollingchanneladapterdemoTests {

  @Autowired
  @Qualifier("dataSource")
  DataSource dataSource;

  private static PollableChannel outputQueue;

    @BeforeClass
    public static void setupClass() {
    outputQueue = MessageChannels.queue().get();
        return;
    }

    @Test
    public void Should_HaveQueue() {
        assertThat(outputQueue, instanceOf(QueueChannel.class));
    }

    @Test
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Create Table DEMO (CODE VARCHAR(5));")
  @Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD,
      statements = "Drop Table DEMO ;")
    public void Should_Not_HaveMessageOnTheQueue_When_No_DemosAreInTheDatabase() {
        Message<?> message = outputQueue.receive(5000);
        assertThat(message, nullValue()) ;
    }

  @Test
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Create Table DEMO (CODE VARCHAR(5));")
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Insert into DEMO (CODE) VALUES ('12345');")
  @Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD,
      statements = "Drop Table DEMO ;")
  public void Should_HaveMessageOnTheQueue_When_DemosIsInTheDatabase() {
    assertThat(outputQueue, instanceOf(QueueChannel.class));
    Message<?> message = outputQueue.receive(5000);
    assertThat(message, notNullValue());
    assertThat(message.getPayload().toString(), equalTo("15317")) ;
  }

  @Test
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Create Table DEMO (CODE VARCHAR(5));")
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Insert into DEMO (CODE) VALUES ('12345');")
  @Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD,
      statements = "Drop Table DEMO ;")
  public void get_message_directly_from_adapter() {
    JdbcPollingChannelAdapter adapter =
        new JdbcPollingChannelAdapter(dataSource, "SELECT CODE FROM DEMO");
    adapter.setRowMapper(new DemoRowMapper());
    adapter.setMaxRowsPerPoll(1);
    Message<?> message = adapter.receive();
    assertThat(message, notNullValue());
  }


  private static class Demo {

    private String demo;

    String getDemo() {
      return demo;
    }

    void setDemo(String value) {
      this.demo = value;
    }

    @Override
    public String toString() {
      return "Demo [value=" + this.demo + "]";
    }
  }

  public static class DemoRowMapper implements RowMapper<Demo> {

    @Override
    public Demo mapRow(ResultSet rs, int rowNum) throws SQLException {
      Demo demo = new Demo();
      demo.setDemo(rs.getString("CODE"));
      return demo;
    }
  }

  @Component
  public static class MyFlowAdapter extends IntegrationFlowAdapter {

    @Autowired
    @Qualifier("dataSource")
    DataSource dataSource;

    @Override
    protected IntegrationFlowDefinition<?> buildFlow() {

      JdbcPollingChannelAdapter adapter =
          new JdbcPollingChannelAdapter(dataSource, "SELECT CODE FROM DEMO");
      adapter.setRowMapper(new DemoRowMapper());
      adapter.setMaxRowsPerPoll(1);

      return from(adapter,
          c -> c.poller(Pollers.fixedRate(1000L, 2000L)
              .maxMessagesPerPoll(1)
              .get()))
          .channel(outputQueue);
    }
  }
}

EDIT I've simplified it as much as I can, refactoring to code below. 编辑我已经尽力简化了,将其重构为以下代码。 The test passes a flow with a generic message source, and fails on a flow with JdbcPollingChannelAdapter message source. 该测试通过带有通用消息源的流,而对于带有JdbcPollingChannelAdapter消息源的流失败。 It's just not evident to me how I should configure the second message source so that it will suceed like the first message source. 对我来说,尚不清楚如何配置第二个消息源,以便像第一个消息源那样获得成功。

  @Test
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Create Table DEMO (CODE VARCHAR(5));")
  @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Insert into DEMO (CODE) VALUES ('12345');")
  public void Should_HaveMessageOnTheQueue_When_UnsentDemosIsInTheDatabase() {

this.genericFlowContext.registration(new GenericFlowAdapter()).register();

PollableChannel genericChannel = this.beanFactory.getBean("GenericFlowAdapterOutput",
    PollableChannel.class);

this.jdbcPollingFlowContext.registration(new JdbcPollingFlowAdapter()).register();

PollableChannel jdbcPollingChannel = this.beanFactory.getBean("JdbcPollingFlowAdapterOutput",
    PollableChannel.class);

assertThat(genericChannel.receive(5000).getPayload(), equalTo("15317"));

assertThat(jdbcPollingChannel.receive(5000).getPayload(), equalTo("15317"));
  }

  private static class GenericFlowAdapter extends IntegrationFlowAdapter {

@Override
protected IntegrationFlowDefinition<?> buildFlow() {
  return from(getObjectMessageSource(),
      e -> e.poller(Pollers.fixedRate(100)))
      .channel(c -> c.queue("GenericFlowAdapterOutput"));
}

private MessageSource<Object> getObjectMessageSource() {
  return () -> new GenericMessage<>("15317");
}
}

private static class JdbcPollingFlowAdapter extends IntegrationFlowAdapter {

@Autowired
@Qualifier("dataSource")
DataSource dataSource;

@Override
protected IntegrationFlowDefinition<?> buildFlow() {
  return from(getObjectMessageSource(),
      e -> e.poller(Pollers.fixedRate(100)))
      .channel(c -> c.queue("JdbcPollingFlowAdapterOutput"));
}

private MessageSource<Object> getObjectMessageSource() {
  JdbcPollingChannelAdapter adapter =
      new JdbcPollingChannelAdapter(dataSource, "SELECT CODE FROM DEMO");
  adapter.setRowMapper(new DemoRowMapper());
  adapter.setMaxRowsPerPoll(1);
  return adapter;
}
  }

Looks like you need to add @EnableIntegration to your test configuration. 看起来您需要在测试配置中添加@EnableIntegration When you use Spring Boot slices for testing, not all auto-configurations are loaded: 当您使用Spring Boot slice进行测试时,并非所有自动配置都被加载:

https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#test-auto-configuration https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/htmlsingle/#test-auto-configuration

UPDATE UPDATE

The problem that JdbcPollingChannelAdapter is run in the separate, scheduled thread, already out of the original transaction around test method, where those @Sql s are performed. JdbcPollingChannelAdapter在单独的预定线程中运行的问题已经在测试方法(执行这些@Sql周围的原始事务中@Sql了。

The fix for you is like this: 解决方法如下:

@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD,
      statements = "Insert into DEMO (CODE) VALUES ('12345');",
      config = @SqlConfig(transactionMode = SqlConfig.TransactionMode.ISOLATED))

Pay attention to that SqlConfig.TransactionMode.ISOLATED . 注意该SqlConfig.TransactionMode.ISOLATED This way the INSERT transaction is committed and the data is available for that separate polling thread for the JdbcPollingChannelAdapter . 这样,将提交INSERT事务,并且该数据可用于JdbcPollingChannelAdapter单独的轮询线程。

Also pay attention that this JdbcPollingChannelAdapter always returns a List of records. 还请注意,此JdbcPollingChannelAdapter始终返回记录List So, your assertThat(jdbcPollingChannel.receive(5000).getPayload(), ...); 因此,您的assertThat(jdbcPollingChannel.receive(5000).getPayload(), ...); should be against a List<String> even if there is only one record in the table. 即使表中只有一条记录,也应针对List<String>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM