关于java:Spring Integration在下一步之前完成异步转换

Spring Integration complete asynchronous transformation before the next

我有一个集成流,该流会定期轮询数据库以检索尚未处理的所有MachineLine实体并对其进行处理。该流程检索MachineLine对象的集合,然后我希望将其拆分为单个对象,将这些对象转换为ReportDetails对象,并将转换后的对象持久保存在数据库中的另一个表中。流程定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Bean
public IntegrationFlow processMachineLine() {
    return IntegrationFlows
            .from(Jpa.inboundAdapter(this.entityManager)
                            .entityClass(MachineLine.class)
                            .jpaQuery(this.machineService.retrieveUnprocessedLinesQuery()),
                    e -> e.poller(Pollers.fixedDelay(5000)))
            .split()
            .transform(MachineLine.class, this::transformMachineLineToReportDetails)
            .handle(Jpa.outboundAdapter(this.entityManager)
                            .entityClass(ReportDetails.class),
                    ConsumerEndpointSpec::transactional)
            .get();
}

上面的定义工作正常,但是速度很慢。 transformMachineLineToReportDetails方法将HTTP请求发送到另一个服务,该服务需要花费几秒钟的时间进行响应。使用当前流定义,每个MachineLine对象都将等待前一个对象被转换并持久化,然后再对它们进行相同的处理。

因此,理想的解决方案是异步执行此转换和持久性。一种可能的解决方案是在.split().transform(...)之间插入以下行:

.channel(new ExecutorChannel(Executors.newCachedThreadPool()))

但是,这允许JPA入站适配器在处理和保留上次轮询的结果之前再次轮询数据库。这意味着,上一次数据库轮询返回的所有未转换且在下一次轮询之前仍未保留的MachineLine实体将被第二次检索,并尝试进行第二次转换和持久化。显然,这会导致不必要的资源成本,并且当多个具有相同ID的ReportDetails对象试图保留到数据库时,也会产生错误。

有没有一种方法可以异步转换MachineLine对象,但要确保直到上一次轮询的结果完成了对流程的遍历(即,所有MachineLine对象都已转换并坚持)?


我通过自定义AbstractMessageSourceAdvice看到某些AtomicBoolean标志(也可以是bean)以检入beforeReceive()的唯一方法。由于您使用Pollers.fixedDelay(5000),因此您的轮询策略仍然是单线程的。因此,在AbstractMessageSourceAdvice不允许的情况下,最好不要让同一个线程对JPA执行轮询。乞讨中的布尔标志应为true,并在提到的split()之前将其更改为false。您可以使用publishSubscribeChannel()作为两个订阅者来执行此操作。甚至在AbstractMessageSourceAdvice实现中执行该操作-在该beforeReceive()实现中还算compareAndSet(true, false)

然后使用ExecutorChannel进行转换后拆分并保留。

在流程的最后,您需要放置具有两个订户的publishSubscribeChannel()-1。handle(Jpa.outboundAdapter(this.entityManager); 2. aggregate()等待所有拆分项目完成。在aggregate()之后,放置一个简单的handle(m -> pollingFlagBean().set(true))

仅此而已:仅当所有项目都已处理并汇总到组中时,才会进行新的轮询。之后,您才能使用该AtomicBoolean再次轮询。

您还可以考虑将此标志逻辑与SimpleActiveIdleMessageSourceAdvice结合使用,以在主动模式和被动模式之间更改轮询周期,从而避免在等待聚合时出现较大的空闲时间。

任何其他异步解决方案仍然不适合您,因为切换到其他线程将立即释放轮询过程以使其再次旋转。