Spring Integration中的REST端点使消息传递通道成为多线程

时间:2017-07-27 23:44:18

标签: java rest spring-boot spring-integration spring-integration-sftp

我有一个非常简单的Spring Boot应用程序,它提供了几个安静的端点,这应该驱动一个sftp文件上传到sftp服务器。我的要求是,如果有多个文件,文件应该排队。我希望通过sftp spring集成工作流的默​​认行为来实现这一点,因为我读到DirectChannel会自动对文件进行排队。为了测试行为,我执行以下操作:

  1. 发送一个大文件,通过调用端点阻止频道一段时间。
  2. 通过调用端点发送较小的文件。
  3. 预期结果:较小的文件排队到通道上,并在上传较大的文件完成后进行处理。 实际结果:打开了与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时都会创建一个新的。在这种情况下,如何实现队列行为的任何帮助都将不胜感激。

1 个答案:

答案 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