Spring integration 同时为每个Ftp文件运行Spring集成流

Spring integration 同时为每个Ftp文件运行Spring集成流,spring-integration,spring-integration-dsl,spring-integration-sftp,Spring Integration,Spring Integration Dsl,Spring Integration Sftp,我有一个使用Java DSL配置的集成流,它使用Ftp.inboundChannelAdapter从Ftp服务器提取文件,然后将其转换为JobRequest,然后我有一个.handle()方法触发批处理作业,所有操作都按照要求进行,但FTP文件夹中的每个文件的进程都在按顺序运行 我在Transformer端点中添加了currentThreadName,它为每个文件打印相同的线程名称 这是我到现在为止一直在尝试的 1.任务执行器bean @Bean public TaskExecutor

我有一个使用Java DSL配置的集成流,它使用
Ftp.inboundChannelAdapter
从Ftp服务器提取文件,然后将其转换为
JobRequest
,然后我有一个
.handle()
方法触发批处理作业,所有操作都按照要求进行,但FTP文件夹中的每个文件的进程都在按顺序运行

我在Transformer端点中添加了
currentThreadName
,它为每个文件打印相同的线程名称

这是我到现在为止一直在尝试的

1.任务执行器bean

 @Bean
    public TaskExecutor taskExecutor(){
        return new SimpleAsyncTaskExecutor("Integration");

    }
2.整合流程

  @Bean
public IntegrationFlow integrationFlow(JobLaunchingGateway jobLaunchingGateway) throws IOException {
    return IntegrationFlows.from(Ftp.inboundAdapter(myFtpSessionFactory)
                    .remoteDirectory("/bar")
                    .localDirectory(localDir.getFile())
            ,c -> c.poller(Pollers.fixedRate(1000).taskExecutor(taskExecutor()).maxMessagesPerPoll(20)))
            .transform(fileMessageToJobRequest(importUserJob(step1())))
            .handle(jobLaunchingGateway)
            .log(LoggingHandler.Level.WARN, "headers.id + ': ' + payload")
            .route(JobExecution.class,j->j.getStatus().isUnsuccessful()?"jobFailedChannel":"jobSuccessfulChannel")
            .get();
}
3.我还读入了另一个SO线程,我需要
ExecutorChannel
,所以我配置了一个,但我不知道如何将此通道注入我的
Ftp。inboundAdapter
,从日志中可以看到该通道始终是
integrationFlow.channel#0
,我猜它是
DirectChannel

 @Bean
public MessageChannel inputChannel() {
    return new ExecutorChannel(taskExecutor());
}
我不知道我在这里遗漏了什么,或者我可能没有正确理解Spring消息传递系统,因为我对Spring和Spring集成非常陌生

谢谢你的帮助


感谢您可以简单地将
ExecutorChannel
注入到流中,框架将把它应用到
SourcePollingChannelAdapter
。因此,将
inputChannel
定义为bean,您只需执行以下操作:

.channel(inputChannel())
在您的
.transform(fileMessageToJobRequest(importUserJob(step1()))之前)
。 请参阅文档中的更多内容:

另一方面,要根据
.taskExecutor(taskExecutor())
配置并行处理文件,只需将
.maxMessagesPerPoll(20)
设置为
1
AbstractPollingEndpoint
中的逻辑如下:

this.taskExecutor.execute(() -> {
                int count = 0;
                while (this.initialized && (this.maxMessagesPerPoll <= 0 || count < this.maxMessagesPerPoll)) {
                    if (pollForMessage() == null) {
                        break;
                    }
                    count++;
                }
this.taskExecutor.execute(()->{
整数计数=0;

虽然(this.initialized&&(this.maxMessagesPerPollExecutorChannel
您可以简单地注入到流中,它将被框架应用到
SourcePollingChannelAdapter
。因此,将
inputChannel
定义为bean,您只需执行以下操作:

.channel(inputChannel())
在您的
.transform(fileMessageToJobRequest(importUserJob(step1()))之前)
。 请参阅文档中的更多内容:

另一方面,要根据
.taskExecutor(taskExecutor())
配置并行处理文件,只需将
.maxMessagesPerPoll(20)
设置为
1
AbstractPollingEndpoint
中的逻辑如下:

this.taskExecutor.execute(() -> {
                int count = 0;
                while (this.initialized && (this.maxMessagesPerPoll <= 0 || count < this.maxMessagesPerPoll)) {
                    if (pollForMessage() == null) {
                        break;
                    }
                    count++;
                }
this.taskExecutor.execute(()->{
整数计数=0;

while(this.initialized&&(this.maxMessagesPerPoll),因此pollerspec中的
taskExecutor()
方法允许poller轮询消息并将其交给另一个线程,然后将轮询的线程释放以轮询下一组消息…是这样吗?是的,这是正确的。至少有两个线程:一个用于根据触发器配置安排定期任务。另一个(或多个)用于执行轮询任务。因此,是的,当在不同的线程上执行此类轮询任务时,控制返回调度程序以启动新的周期性任务。从技术上讲,下游
ExecutorChannel
将给我们带来类似的副作用-只要我们将作业转移到不同的线程,调度程序就可以执行此任务e下一个轮询周期。在我将
maxMessagesPerPoll
更改为1后,每个文件的批处理作业现在在不同的线程上运行,即使我没有
ExecutorChannel
,因此当轮询器一次读取两条或多条消息并将其交给
ExecutorChannel
时,
ExecutorChannel
非常有用e通道在不同的线程上同时处理每条消息。
ExecutorChannel
在我将
maxMessagesPerPoll
设置为1时不是必需的。正确吗?只需再次澄清我的疑问我知道你在回答中解释了类似的问题。你的观察是正确的:确实没有必要增加线程的开销如果这对您的逻辑来说足够的话,则进行移位。因此pollerspec中的
taskExecutor()
方法允许poller轮询消息并将其交给另一个线程,然后将轮询的线程释放以轮询下一组消息…是这样吗?是的,这是正确的。至少有两个线程:一个用于根据触发器配置安排定期任务。另一个(或多个)用于执行轮询任务。因此,是的,当在不同的线程上执行此类轮询任务时,控制返回调度程序以启动新的周期性任务。从技术上讲,下游
ExecutorChannel
将给我们带来类似的副作用-只要我们将作业转移到不同的线程,调度程序就可以执行此任务e下一个轮询周期。在我将
maxMessagesPerPoll
更改为1后,每个文件的批处理作业现在在不同的线程上运行,即使我没有
ExecutorChannel
,因此当轮询器一次读取两条或多条消息并将其交给
ExecutorChannel
时,
ExecutorChannel
非常有用e通道在不同的线程上同时处理每条消息。
ExecutorChannel
在我将
maxMessagesPerPoll
设置为1时不是必需的。正确吗?只需再次澄清我的疑问我知道你在回答中解释了类似的问题。你的观察是正确的:确实没有必要增加线程的开销如果这对你的逻辑足够的话。