从SFTP出站网关获取输入流时有时没有消息
这是后续问题 Use SFTP Outbound Gateway to Obtain Input Stream
我在上一个问题中遇到的问题似乎是我没有关闭int:service-activator中显示的流。但是,当我添加int:service-activator时,我似乎被迫添加int:poller。
但是,当我添加int:poller时,我注意到有时现在尝试获取流时消息为空。我发现一个解决方法是简单地重试。我已经测试了不同的文件,似乎小文件受到不利影响,大文件不是。所以,如果我不得不猜测,必须有一个竞争条件,其中int:service-activator在我尝试调用getInputStream()之前关闭会话但是我希望有人可以解释这是否是实际发生的事情以及是否存在是一个更好的解决方案,而不仅仅是简单的重试?
谢谢!
以下是出站网关配置:
<int-ftp:outbound-gateway session-factory="ftpClientFactory"
request-channel="inboundGetStream" command="get" command-options="-stream"
expression="payload" remote-directory="/" reply-channel="stream">
</int-ftp:outbound-gateway>
<int:channel id="stream">
<int:queue/>
</int:channel>
<int:poller default="true" fixed-rate="50" />
<int:service-activator input-channel="stream"
expression="payload.toString().equals('END') ? headers['file_remoteSession'].close() : null" />
以下是获取InputStream的源代码:
public InputStream openFileStream(final int retryCount, final String filename, final String directory)
throws Exception {
InputStream is = null;
for (int i = 1; i <= retryCount; ++i) {
if (inboundGetStream.send(MessageBuilder.withPayload(directory + "/" + filename).build(), ftpTimeout)) {
is = getInputStream();
if (is != null) {
break;
} else {
logger.info("Failed to obtain input stream so attempting retry " + i + " of " + retryCount);
Thread.sleep(ftpTimeout);
}
}
}
return is;
}
private InputStream getInputStream() {
Message<?> msgs = stream.receive(ftpTimeout);
if (msgs == null) {
return null;
}
InputStream is = (InputStream) msgs.getPayload();
return is;
}
更新,我会继续接受唯一的答案,因为它足以找到解决方案。
原始问题的答案接受了回答令人困惑,因为它回答了一个带有xml配置解决方案的java问题,虽然解释了问题并没有真正提供必要的java技术解决方案。这个后续问题/答案澄清了弹簧整合中的情况,并提出了解决问题的建议。
最终解决方案。为了以后获取并保存流,我不得不创建一个bean来保存流以供以后参考。此流是从邮件头获取的。
注意,为简洁起见,省略了错误检查和getter / setter:
使用与上述问题相同的xml配置,但删除了poller和service-activator元素,因为它们是不必要的并且导致错误。
创建一个新类SftpStreamSession以保存必要的引用:
public class SftpStreamSession {
private Session<?> session;
private InputStream inputStream;
public void close() {
inputStream.close();
session.close();
}
}
更改openFileStream方法以返回SftpStreamSession:
public SftpStreamSession openFileStream(final String filename, final String directory) throws Exception {
SftpStreamSession sss = null;
if (inboundGetStream.send(MessageBuilder.withPayload(directory + "/" + filename).build(), ftpTimeout)) {
Message<?> msgs = stream.receive(ftpTimeout);
InputStream is = (InputStream) msgs.getPayload();
MessageHeaders mH = msgs.getHeaders();
Session<?> session = (Session<?>) mH.get("file_remoteSession");
sss = new SftpStreamSession(session, is);
}
return sss;
}
答案 0 :(得分:0)
首先,您不需要payload.toString().equals('END')
,因为您的逻辑中似乎没有使用<int-file:splitter>
。
二。您不需要那个丑陋的<service-activator>
,因为您可以完全访问代码中的消息。您只需获取file_remoteSession
,将其投放到Session<?>
并在逻辑结尾处调用.close()
。
是的,存在竞争条件,但它会发生在您的代码中。
看,您有stream
QueueChannel
。从一开始你就有一个消费者stream.receive(ftpTimeout);
。但现在你已经介绍了<int:service-activator input-channel="stream">
。因此,一个竞争消费者。如此小的(fixed-rate="50"
)轮询间隔确实会导致您出现意外行为。