如何通过DirectChannel在消息处理后执行与入站流相关的成功操作

时间:2015-09-22 20:57:31

标签: spring-integration

这个问题更像是一个设计问题,而不是一个真正的问题。给出以下基本流程:

@Bean
public DirectChannel getFileToSftpChannel() {
    return new DirectChannel();
}

@Bean
public IntegrationFlow sftpOutboundFlow() {
        return IntegrationFlows.from(getFileToSftpChannel())
                .handle(Sftp.outboundAdapter(this.sftpSessionFactory)
                                .useTemporaryFileName(false)
                                .remoteDirectory("test")).get();
    }
@Bean
public IntegrationFlow filePollingInboundFlow() {
    return from(s -> s.file(new File("path")).patternFilter("*.ext"),
            e -> e.poller(fixedDelay(60, SECONDS).channel(getFileToSftpChannel()).get();
}

有一个入站文件轮询流,它通过DirectChannel将消息发布到上传文件的出站SFTP流。 整个流程完成后,我想执行“成功”操作:将原始文件(本地)移动到存档文件夹。 使用DirectChannel,我知道上传将发生在与文件轮询相同的线程中。 换句话说,文件轮询器阻止直到上载完成(或者返回错误消息,然后将其推送到错误通道)。 知道了这一点,我想在入站流程中放置“成功”动作(=移动原始文件)。我已经知道并且不想使用的事情:

  • sftpOutbound上的另一个“句柄”。原因:移动文件与inboud流而不是出站流相关联。对于前者如果我稍后会引入另一个,第二个,生产者(例如JMS入站流)发布到同一个频道,那么就不会有“文件”被移动。
  • 在DirectChannel上添加拦截器并使用'afterSendCompletion'。原因:与上述相同,我希望逻辑与入站流程相关联
  • 在入站流中添加事务语义并对'commit'作出反应。原因:由于所有这些都是非事务性的(基于文件系统/ SFTP),我想避免使用它。

我尝试的另一件事是在入站流程中添加“句柄”。但是,我了解到入站流没有真正的'回复',句柄在发送消息之前执行,所以这不起作用,因为必须在成功处理消息后执行移动。

简而言之:在消费者(=出站流)通过DirectChannel成功处理消息后,执行生产者(=入站流)提供的操作的标准方法是什么?

2 个答案:

答案 0 :(得分:0)

嗯,做类似事情的标准方法是transaction,这就是为什么我们前一段时间介绍PseudoTransactionManager和类似任务的XML示例看起来像:

<int-file:inbound-channel-adapter id="realTx" channel="txInput" auto-startup="false"
                         directory="${java.io.tmpdir}/si-test2">
    <int:poller fixed-rate="500">
        <int:transactional synchronization-factory="syncFactory"/>
    </int:poller>
</int-file:inbound-channel-adapter>

<bean id="transactionManager" class="org.springframework.integration.transaction.PseudoTransactionManager"/>

<int:transaction-synchronization-factory id="syncFactory">
    <int:after-commit expression="payload.delete()"/>
</int:transaction-synchronization-factory>

如您所见,我们在交易结束时删除了文件,这是在您转移到SFTP之后造成的。

我说这是与制片人联系的最佳方式。

另一种方法是在getFileToSftpChannel()之前引入另一个频道,并应用最终将被调用的ChannelInterceptor.afterSendCompletion,同样的单线程原因。使用这种方法,您应该bridge所有生产者使用特定DirectChannel s到SFTP适配器的单getFileToSftpChannel()

所以,它取决于你选择什么。从架构的角度来看,你有很好的论据可以将逻辑划分为责任层,但正如你所看到的,没有那么多的选择......

欢迎任何其他想法!

答案 1 :(得分:0)

您可以尝试以下内容

@Bean
public DirectChannel getFileToSftpChannel() {
DirectChannel directChannel = new DirectChannel();
directChannel.addInterceptor(new ChannelInterceptorAdapter() {
@Override
public void afterSendCompletion(final Message<?> message, 
final MessageChannel channel, final boolean sent, final Exception ex) {
if (ex == null) {
new Archiver().archive((File) message.getPayload());
}
}
});
return directChannel;
}