如何在同一应用程序中更好地关联Spring集成TCP入站和出站适配器?

如何在同一应用程序中更好地关联Spring集成TCP入站和出站适配器?,spring,spring-boot,tcp,spring-integration,Spring,Spring Boot,Tcp,Spring Integration,我目前有一个Spring集成应用程序,它利用许多TCP入站和出站适配器组合来处理消息。所有这些适配器组合使用相同的单一MessageEndpoint进行请求处理,使用相同的单一MessagingGateway进行响应发送 MessageEndpoint的最终输出通道是一个DirectChannel,也是MessageGateway的DefaultRequestChannel。此DirectChannel利用默认的RoundRobinLoadBalancing策略,对正确的出站适配器进行循环搜索,

我目前有一个Spring集成应用程序,它利用许多TCP入站和出站适配器组合来处理消息。所有这些适配器组合使用相同的单一MessageEndpoint进行请求处理,使用相同的单一
MessagingGateway
进行响应发送

MessageEndpoint的最终输出通道是一个
DirectChannel
,也是MessageGateway的DefaultRequestChannel。此
DirectChannel
利用默认的
RoundRobinLoadBalancing策略
,对正确的出站适配器进行循环搜索,以通过发送给定响应。当然,这种循环搜索并不总是在第一次搜索时找到合适的出站适配器,如果没有找到,它会相应地记录。这不仅会产生大量不需要的日志记录,而且还会引起一些性能问题,因为我预计在任何给定时间都会存在数百个入站/出站适配器组合

我想知道是否有一种方法可以更紧密地关联入站适配器和出站适配器,而不需要循环处理,并且每个响应都可以直接发送到相应的出站适配器?理想情况下,我希望以一种可以保持使用单个
MessageEndpoint
和单个
MessageGateway
的方式来实现这一点

注意:请将解决方案限制为使用入站/出站适配器组合的解决方案。我的实现不可能使用TcpInbound/TcpOutboundGateways,因为我需要对单个请求发送多个响应,据我所知,这只能通过使用入站/出站适配器来完成

为了更清楚,下面是当前实现的浓缩版本。我试图清除任何不相关的代码,只是为了让事情更容易阅读

// Inbound/Outbound Adapter creation (part of a service that is used to dynamically create varying number of inbound/outbound adapter combinations)
public void configureAdapterCombination(int port) {

    TcpNioServerConnectionFactory connectionFactory = new TcpNioServerConnectionFactory(port);
    // Connection Factory registered with Application Context bean factory (removed for readability)...

    TcpReceivingChannelAdapter inboundAdapter = new TcpReceivingChannelAdapter();
    inboundAdapter.setConnectionFactory(connectionFactory);
    inboundAdapter.setOutputChannel(context.getBean("sendFirstResponse", DirectChannel.class));
    // Inbound Adapter registered with Application Context bean factory (removed for readability)...

    TcpSendingMessageHandler outboundAdapter = new TcpSendingMessageHandler();
    outboundAdapter.setConnectionFactory(connectionFactory);
    // Outbound Adapter registered with Application Context bean factory (removed for readability)...

    context.getBean("outboundResponse", DirectChannel.class).subscribe(outboundAdapter);

}

// Message Endpoint for processing requests
@MessageEndpoint
public class RequestProcessor {

    @Autowired
    private OutboundResponseGateway outboundResponseGateway;

    // Direct Channel which is using Round Robin lookup
    @Bean
    public DirectChannel outboundResponse() {
        return new DirectChannel();
    }

    // Removed additional, unrelated, endpoints for readability...

    @ServiceActivator(inputChannel="sendFirstResponse", outputChannel="sendSecondResponse")
    public Message<String> sendFirstResponse(Message<String> message) {
        // Unrelated message processing/response generation excluded...
        outboundResponseGateway.sendOutboundResponse("First Response", message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class));
        return message;
    }

    // Service Activator that puts second response on the request channel of the Message Gateway
    @ServiceActivator(inputChannel = "sendSecondResponse", outputChannel="outboundResponse")
    public Message<String> processQuery(Message<String> message) {
        // Unrelated message processing/response generation excluded...
        return MessageBuilder.withPayload("Second Response").copyHeaders(message.getHeaders()).build();
    }

}

// Messaging Gateway for sending responses
@MessagingGateway(defaultRequestChannel="outboundResponse")
public interface OutboundResponseGateway {
    public void sendOutboundResponse(@Payload String payload, @Header(IpHeaders.CONNECTION_ID) String connectionId);
}
//入站/出站适配器创建(用于动态创建不同数量的入站/出站适配器组合的服务的一部分)
公共无效配置适配器组合(int端口){
TcpNioServerConnectionFactory connectionFactory=新的TcpNioServerConnectionFactory(端口);
//已向应用程序上下文bean工厂注册的连接工厂(为可读性而删除)。。。
TCPrecivingChannelAdapter inboundAdapter=新的TCPrecivingChannelAdapter();
inboundAdapter.setConnectionFactory(connectionFactory);
setOutputChannel(context.getBean(“sendFirstResponse”,DirectChannel.class));
//已向应用程序上下文bean工厂注册的入站适配器(为可读性而删除)。。。
TcpSendingMessageHandler outboundAdapter=新的TcpSendingMessageHandler();
outboundAdapter.setConnectionFactory(connectionFactory);
//向应用程序上下文bean工厂注册的出站适配器(为可读性而删除)。。。
getBean(“outboundResponse”,DirectChannel.class).subscribe(outboundAdapter);
}
//用于处理请求的消息端点
@消息端点
公共类请求处理器{
@自动连线
私人外围通道外围通道;
//使用循环查找的直接通道
@豆子
公共DirectChannel outboundResponse(){
返回新的DirectChannel();
}
//已删除其他无关端点以提高可读性。。。
@ServiceActivator(inputChannel=“sendFirstResponse”,outputChannel=“sendSecondResponse”)
公共消息sendFirstResponse(消息消息消息){
//不相关的消息处理/响应生成已排除。。。
outboundResponseGateway.sendOutboundResponse(“第一个响应”,message.getHeaders().get(IpHeaders.CONNECTION_ID,String.class));
返回消息;
}
//在消息网关的请求通道上放置第二个响应的服务激活器
@ServiceActivator(inputChannel=“sendSecondResponse”,outputChannel=“outboundResponse”)
公共消息处理查询(消息消息){
//不相关的消息处理/响应生成已排除。。。
返回MessageBuilder.withPayload(“第二个响应”).copyHeaders(message.getHeaders()).build();
}
}
//用于发送响应的消息传递网关
@MessagingGateway(defaultRequestChannel=“outboundResponse”)
公共接口外围通道{
public void sendOutboundResponse(@Payload String Payload,@Header(IpHeaders.CONNECTION_ID)String connectionId);
}
解决方案:

@下面的评论/答案中Artem的建议似乎起到了作用。我只是想简要说明一下我是如何在创建时向每个出站适配器添加一个
replyChannel

我所做的是创建两个由应用程序维护的映射。每当创建新的入站/出站适配器组合时,将填充第一个映射,它是
ConnectionFactory
name到
replyChannel
name的映射。第二个映射是
ConnectionId
replyChannel
名称的映射,它通过
EventListener
填充到任何新的上

请注意,每个
TcpConnectionOpenEvent
都将有一个
ConnectionFactoryName
ConnectionId
属性,该属性是根据建立连接的位置/方式定义的

从那里,每当收到新的请求时,我都会使用这些映射和上的“ip_connectionId”头向消息添加
replyChannel
头。第一个响应是通过从应用程序的上下文中手动获取相应的
replyChannel
(基于
replyChannel
头的值)并在该通道上发送响应来发送的。第二个响应使用消息上的
replyChannel
头通过Spring集成发送