我有一个非常简单的Spring Boot应用程序,它提供了几个安静的端点,这应该驱动一个sftp文件上传到sftp服务器。我的要求是,如果有多个文件,文件应该排队。我希望通过sftp spring集成工作流的默认行为来实现这一点,因为我读到DirectChannel会自动对文件进行排队。为了测试行为,我执行以下操作:
预期结果:较小的文件排队到通道上,并在上传较大的文件完成后进行处理。 实际结果:打开了与sftp服务器的新连接,并在不排队的情况下上传较小的文件,而较大的文件继续传输。
我的应用程序中有两个文件:
DemoApplication.java
@SpringBootApplication
@IntegrationComponentScan
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public SessionFactory<LsEntry> sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost("localhost");
factory.setPort(22);
factory.setUser("tester");
factory.setPassword("password");
factory.setAllowUnknownKeys(true);
return factory;
}
@Bean
@ServiceActivator(inputChannel = "toSftpChannel")
public MessageHandler handler() {
SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
handler.setRemoteDirectoryExpression(new LiteralExpression("/"));
return handler;
}
@MessagingGateway
public interface MyGateway {
@Gateway(requestChannel = "toSftpChannel")
void sendToSftp(File file);
}
}
DemoController.java
@RestController
public class DemoController {
@Autowired
MyGateway gateway;
@RequestMapping("/sendFile")
public void sendFile() {
File file = new File("C:/smallFile.txt");
gateway.sendToSftp(file);
}
@RequestMapping("/sendBigFile")
public void sendBigFile() {
File file = new File("D:/bigFile.zip");
gateway.sendToSftp(file);
}
}
我是一个完全新手的春天,我不确定我的sftp频道是否在这里正确创建,我的猜测是每次我发送sendToSftp时都会创建一个新的。在这种情况下,如何实现队列行为的任何帮助都将不胜感激。
答案 0 :(得分:2)
此处没有队列,因为每个HTTP请求都在自己的线程中执行。是的,无论如何,当http线程池耗尽时,你可能会在那里排队,但只有两个请求就不会出现在你的简单用例中。
无论如何,您可以在那里实现队列行为,但是您应该将toSftpChannel
声明为QueueChannel
bean。
这样下游进程将始终在同一个线程上执行,下一条消息将在第一个消息之后完全从队列中提取。
有关详细信息,请参阅Reference Manual。
<强>更新强>
由于您使用的FtpMessageHandler
是单向组件,但您仍然需要对MVC控制器的方法进行一些回复,因此只有这样做的方法是使用@Gateway
方法使用非{ {1}}返回,当然我们需要以某种方式发送回复。
为此,我建议使用void
:
PublishSubscribeChannel
这样我们就有@Bean
@BridgeTo
public MessageChannel toSftpChannel() {
return new PublishSubscribeChannel();
}
@Bean
@ServiceActivator(inputChannel = "toSftpChannel")
@Order(0)
public MessageHandler handler() {
SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
handler.setRemoteDirectoryExpression(new LiteralExpression("/"));
return handler;
}
的两个订阅者。使用toSftpChannel
,我们确保@Order(0)
是第一个订户,因为我们需要先执行SFTP传输。使用@ServiceActivator
,我们会向同一@BridgeTo
添加第二个BridgeHandler
。其目的只是获取PublishSubscribeChannel
标头并在那里发送请求消息。由于我们不使用任何线程,replyChannel
将在完成转移到SFTP后完成。
当然,代替BridgeHandler
,您可以让任何其他BridgeHandler
或@ServiceActivator
作为回复而不是请求@Transfromer
,而是其他任何内容。例如:
File