TCP Gateways
输入 TCP 网关 TcpInboundGateway
和输出 TCP 网关 TcpOutboundGateway
分别使用服务器和客户端连接工厂。每个连接一次只能处理单个请求或响应。
在通过传入有效负载构建消息并将其发送到 requestChannel
后,输入网关将等待响应,并通过将有效负载从响应消息中写入连接来发送响应消息的有效负载。
对于入站网关,你必须保留或填充 |
与输入适配器一样,输入网关通常使用 type="server"
连接工厂,该工厂侦听传入的连接请求。在某些情况下,您可能希望反向建立连接,例如,输入网关连接到外部服务器,然后等待并回复该连接上的传入消息。
输入网关上的 client-mode="true"
支持此拓扑。在这种情况下,连接工厂必须是 client
类型的,并且必须将 single-use
设置为 false
。
还有两个附加属性支持此机制。retry-interval
(以毫秒为单位)指定框架在连接失败后尝试重新连接的频率。scheduler
提供一个 TaskScheduler
来调度连接尝试并测试连接是否仍然处于活动状态。
如果网关已启动,您可以通过发送 <control-bus/>
命令强制网关建立连接:@adapter_id.retryConnection()
,并使用 @adapter_id.isClientModeConnected()
检查当前状态。
outbound 网关在通过连接发送消息之后,将等待响应、构建响应消息,并将其放在 reply 通道上。连接上的通信是单线程的。一次只能处理一个消息。如果另一个线程尝试在收到当前响应之前发送消息,它将阻塞,直至任何先前的请求完成(或超时)。但是,如果客户端连接工厂配置为仅限单次使用的连接,则每个新请求都会获取其自己的连接并立即处理。以下示例配置了一个 inbound TCP 网关:
<int-ip:tcp-inbound-gateway id="inGateway"
request-channel="tcpChannel"
reply-channel="replyChannel"
connection-factory="cfServer"
reply-timeout="10000"/>
如果使用配置了默认序列化器或反序列化器的连接工厂,message 将是 \r\n
分隔数据,网关可以由 telnet 等简单客户端使用。
以下示例显示了一个 outbound TCP 网关:
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="tcpChannel"
reply-channel="replyChannel"
connection-factory="cfClient"
request-timeout="10000"
remote-timeout="10000"/> <!-- or e.g. remote-timeout-expression="headers['timeout']" -->
client-mode
当前在 outbound 网关中不可用。
从 5.2 版开始,outbound 网关可以用 closeStreamAfterSend
属性配置。如果连接工厂配置为 single-use
(每个请求/回复一个新连接),则网关会关闭输出流;这向服务器发出 EOF 信号。如果服务器使用 EOF 来确定消息的结尾,而不是流中的某个分隔符,但保持连接处于打开状态以接收回复,则这很有用。
通常,调用线程会在网关中阻塞,等待回复(或超时)。从 5.3 版开始,你可以在网关上设置 async
属性,并且发送线程将被释放以执行其他工作。回复(或错误)将在接收线程上发送。这仅适用于使用 TcpNetClientConnectionFactory
的情况,在使用 NIO 时它将被忽略,因为存在竞争条件,即在收到回复后发生的套接字错误可能会在回复之前传递到网关。
当使用共享连接(singleUse=false
)时,在另一个处理过程中,新请求将被阻塞,直到收到当前答复为止。如果你希望在长期连接池上支持并发请求,请考虑使用 CachingClientConnectionFactory
。
从 5.4 版开始,inbound 可以用 unsolicitedMessageChannel
配置。主动的 inbound 消息将发送到此通道,以及延迟的回复(其中客户端超时)。为了在服务器端支持这一点,你现在可以使用连接工厂注册多个 TcpSender
。网关和通道适配器会自动注册它们自己。从服务器发送主动消息时,你必须向发送的消息添加适当的 IpHeaders.CONNECTION_ID
。