当@Autowired 时,SftpRemoteFileTemplate 不适用于 RemoteDirectoryExpression

SftpRemoteFileTemplate does not work with RemoteDirectoryExpression when @Autowired

以下是我使用的配置

@Autowired
private SftpRemoteFileTemplate outboundTemplate;

@Autowired
private SftpConfig config;


@Bean
@ServiceActivator(inputChannel = "sftpOutputGenericChannel")
public MessageHandler simplehandler() {
    SftpMessageHandler handler = new SftpMessageHandler(outboundTemplate, FileExistsMode.APPEND);
    handler.setRemoteDirectoryExpression(new LiteralExpression(config.getDirectory()));
    handler.setFileNameGenerator((Message<?> message) -> ((String) message.getHeaders().get(KEY)));
    handler.setUseTemporaryFileName(false);
    return handler;
}

我在单独的配置中创建了 Sessionfactory、CachingSessionfactory 和 SftpRemoteFileTemplte class,并且它们正在正确实例化,下面是相同的日志。

2020-11-27 01:15:17.742 [main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'cachingSessionFactory'
2020-11-27 01:15:17.744 [main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'sftpSessionFactory'
2020-11-27 01:15:17.778 [main] o.s.b.f.s.DefaultListableBeanFactory     : Autowiring by type from bean name 'cachingSessionFactory' via factory method to bean named 'sftpSessionFactory'
2020-11-27 01:15:17.783 [main] o.s.integration.util.SimplePool          : Target pool size changed by -2147483637, now 10
2020-11-27 01:15:54.434 [main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'outboundTemplate'
2020-11-27 01:15:54.435 [main] o.s.b.f.s.DefaultListableBeanFactory     : Autowiring by type from bean name 'outboundTemplate' via factory method to bean named 'cachingSessionFactory'

当我执行这段代码时Spring调试日志显示文件已成功发送到服务器,但实际上文件没有上传到服务器。

但如果我将 MessageHandler 的实现更改为

SftpMessageHandler handler = new SftpMessageHandler(new SftpRemoteFileTemplate(cachingSessionFactory), FileExistsMode.APPEND);

它开始工作并且文件实际上传到服务器,不确定为什么会这样?

当我将 @Autowired SftpRemoteFileTemplatehandler.setRemoteDirectoryExpressionString("headers['remote_directory']") 一起使用时,再观察一次,效果非常好。

我想了解 SftpRemoteTemplate 在这里是如何工作的,建议的最佳做法是什么?

注意:SpringBoot v2.4.0 Spring 集成:5.4.1,面临与 boot v2.2 类似的问题。6.RELEASE

您可能在其他地方使用了相同的 SftpRemoteFileTemplate,并且您还在那里修改它以获得其他选项。事实上,像 handler.setRemoteDirectoryExpression() 这样的东西对提供的 SftpRemoteFileTemplate:

进行了委托,因此也进行了突变
/**
 * Specify a remote directory path SpEL expression.
 * @param remoteDirectoryExpression the remote directory expression
 * @see RemoteFileTemplate#setRemoteDirectoryExpression(Expression)
 */
public void setRemoteDirectoryExpression(Expression remoteDirectoryExpression) {
    this.remoteFileTemplate.setRemoteDirectoryExpression(remoteDirectoryExpression);
}

因此,当另一个地方进行类似的修改时,您最终会遇到竞争条件,并且您的文件可能会被转移到另一个地方。

最佳做法是将 RemoteFileTemplate 视为 prototype,并且每个通道适配器都有一个实例。或者只是使用另一个 ctor - 仅基于 SessionFactory:

/**
 * @param sessionFactory the session factory.
 * @see FileTransferringMessageHandler#FileTransferringMessageHandler
 * (SessionFactory)
 */
public SftpMessageHandler(SessionFactory<LsEntry> sessionFactory)

我们可能需要修改 FileTransferringMessageHandler 中的逻辑以拒绝外部提供的 RemoteFileTemplate 的突变。欢迎提出 GH 问题,我们将在下一个主要版本中看到我们可以做什么,在那里我们可以做一些重大更改。