Java Config入站文件适配器事务管理

时间:2015-10-29 14:53:21

标签: java spring spring-integration spring-transactions

我有一个简单的IntegrationFlow,我正试图通过事务管理来保护它。从较高级别开始,它会轮询目录中的文件,将该文件gzips到磁盘上的新位置,然后将该第二个文件上载到S3。如果它提交,我想将两个路径发布到一个通道(它们将被删除);如果它回滚,我想将它们发布到不同的渠道(它们将被存档)。

我的(缩写)尝试配置如下所示:

@Bean
public IntegrationFlow fromFileFlow(@Qualifier("inboundMessageDirectory") Path inboundMessageDirectory,
                                    @Qualifier("consumableFileFilter") FileListFilter<File> fileListFilter,
                                    @Qualifier(ChannelNames.TO_GZIP_SERVICE) MessageChannel outbound,
                                    @Qualifier("transactionSynchronizationFactory") TransactionSynchronizationFactory transactionSynchronizationFactory) {
    return IntegrationFlows
            .from(s -> s.file(inboundMessageDirectory.toFile()),
                    e -> e.poller(Pollers
                            .fixedDelay(100)
                            .transactionSynchronizationFactory(transactionSynchronizationFactory)
                            .transactional(new PseudoTransactionManager())
                            .get()))
            .channel(outbound)
            .get();
}

服务如下:

@ServiceActivator(inputChannel = ChannelNames.TO_GZIP_SERVICE, outputChannel = ChannelNames.TO_S3_SERVICE)
public Path gzip(@Payload Path path, @Header(ApplicationHeaders.REFERENCE_ID) String referenceId, @Header(ApplicationHeaders.DATA_TYPE) String dataType,
                 @Header(ApplicationHeaders.BUCKET_END) long bucketEnd) throws IOException {
     // ...
}

@ServiceActivator(inputChannel = ChannelNames.TO_S3_SERVICE)
@Retryable(interceptor = RETRY_INTERCEPTOR_BEAN_NAME)
public void sendToS3(@Payload Path path, @Header(ApplicationHeaders.BUCKET_END) long bucketStart,
                     @Header(ApplicationHeaders.DATA_TYPE) String dataType) throws IOException {
     // ...
}

我的自定义TransactionSynchronizationProcessor(我使用DefaultTransactionSynchronizationFactory)或多或少地实现如下(代码未显示从消息有效负载中提取路径并将其存储在IntegrationResourceHolder的属性中):

@Override
public void processBeforeCommit(IntegrationResourceHolder holder) {
    updatePaths(holder);
}

@Override
public void processAfterCommit(IntegrationResourceHolder holder) {
    updateAndSend(successChannel, holder);
}

@Override
public void processAfterRollback(IntegrationResourceHolder holder) {
    updateAndSend(failureChannel, holder);
}

我的理解是,因为所有插页式频道都是直接频道,所以交易也应包含服务。因为它在之前,提交之后和回滚之后更新,我希望它在开始时访问消息,获取解压缩路径,然后在最后访问它并获取gzip压缩路径 - 然后尝试操作他们。但是,只提取未经过拉链的路径。

显然,我对交易的申请(和理解)缺少了一些东西。我实施所需行为的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

不,你有点误解了。

对于transactionaltransactionSynchronizationFactory,我们只担心source。作为数据的最终结果对于事务资源并不重要。我们需要知道只有提交或rallback交易的状态。

这就是为什么IntegrationResourceHolder具有message属性来携带源数据以在TX结束时担心的原因。

就像尝试在TX结束时仅在数据库事务和数据中成像一样。对,没有那个数据!只有TX的输入很重要。

但是,您可以使用额外的ResourceHolderResourceHolderSynchronization来实现您的要求,以便在S3商店之前使用。简单ThreadLocal也可能有所帮助。但一定要在TX结束时正确清除它。

从另一方面考虑使用headers的{​​{1}}消息来携带您需要的所有内容。为此,s.file从Spring Integration 4.2开始就很有用。