配置动态TCP服务器使用Java DSL将消息发送到客户端连接的Spring Integration

时间:2018-05-30 13:02:53

标签: spring-integration spring-integration-dsl

我正在尝试创建一个集成流程:

Connection A : [ ActiveMq (queue1) ---> TCP Server (1111) ](spring boot Application) ---> [ExternalApplication (client connected to Server running on port (1111))] (Application on different Technology (VB))

Connection B : [ ActiveMq (queue2) ---> TCP Server (2222) ](spring boot Application) ---> [ExternalApplication (client connected to Server running on port (2222))] (Application on different Technology (VB))

以上流程描述了以下场景:

  1. 我有一个弹簧启动应用程序(比如springUtility),它可以与其他技术连接外部应用程序(比如externalutility)。

  2. springutility和externalUtility之间的联系是通过TCP协议。

  3. 两个实用程序之间将有多个连接,如上面的流程图连接A和连接B中所示。

  4. 消息流将从springUtilty到externalutility(单向)

  5. 现在,externalutility可以在客户端模式或服务器模式下运行。所以,如果externalUtility在服务器模式下运行,那么我的弹性将在客户端模式(完成)中也创建多个连接我在下面的代码中运行for循环代码:

  6. 代码:

    flow = IntegrationFlows
                .from(Jms.inboundAdapter(ConnectionFactory())
                        .destination("rec"))
                        .channel(directChannel()).handle(Tcp.outboundAdapter(Tcp.nioClient("172.18.11.22",5555)
                                 .serializer(customSerializer)
                                 .deserializer(customSerializer)
                                 .id(hostConnection.getConnectionNumber()).soTimeout(10000)))
                                .get();
    
        flowRegistration = this.flowContext.registration(flow).id("in.flow").register();
    
    1. 问题:当外部用户在客户端模式下运行时,sp​​ring实用程序应该能够创建一个服务器,外部实用程序将在该服务器上连接,然后它开始接收来自spring实用程序的消息: 我试图以错误的方式实施。

    2. 所以,最后我必须将上述连接作为测试用例来验证流程, 表示spring实用程序已打开服务器端口(1111和2222),外部应用程序与这两个端口连接,并分别从queue1和queue2开始从spring实用程序接收消息。这两个连接都有单独的流程(一旦创建了一个流,那么我们就可以使用for循环来创建我们不需要的连接)。

    3. 代码:

      flow = IntegrationFlows
                  .from(Jms.inboundAdapter(ConnectionFactory())
                          .destination("rec"))
                          .channel(directChannel()).handle(Tcp.outboundAdapter(Tcp.netServer(5555)
                                   .serializer(customSerializer)
                                   .deserializer(customSerializer)
                                   .id(hostConnection.getConnectionNumber()).soTimeout(10000)))
                                  .get();
      
          flowRegistration = this.flowContext.registration(flow).id("in.flow").register();
      

      ` 代码:

      2018-05-30 17:39:39.171  INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer       : Adding {jms:outbound-channel-adapter} as a subscriber to the 'Conn1311out.flow.channel#0' channel
      2018-05-30 17:39:39.172  INFO 15776 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel    : Channel 'application.Conn1311out.flow.channel#0' has 1 subscriber(s).
      2018-05-30 17:39:39.172  INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer       : started org.springframework.integration.config.ConsumerEndpointFactoryBean#3
      2018-05-30 17:39:41.965  INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer       : Adding {ip:tcp-outbound-channel-adapter} as a subscriber to the 'Conn1311in.flow.channel#0' channel
      2018-05-30 17:39:41.965  INFO 15776 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel    : Channel 'application.Conn1311in.flow.channel#0' has 1 subscriber(s).
      2018-05-30 17:39:41.966  INFO 15776 --- [nio-8080-exec-1] .s.i.i.t.c.TcpNetServerConnectionFactory : started Conn1311, port=3333
      2018-05-30 17:39:41.966  INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer       : started org.springframework.integration.config.ConsumerEndpointFactoryBean#4
      2018-05-30 17:39:41.966  INFO 15776 --- [pool-1-thread-1] .s.i.i.t.c.TcpNetServerConnectionFactory : Conn1311, port=3333 No listener bound to server connection factory; will not read; exiting...
      2018-05-30 17:39:41.971  INFO 15776 --- [nio-8080-exec-1] o.s.i.e.SourcePollingChannelAdapter      : started org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
      

      首先在提供的端口上创建服务器,但退出并显示以下消息

      No listener bound to server connection factory; will not read; exiting...

      当我创建客户端时它工作正常但是在创建服务器的情况下它给出了错误

      编辑:

      我使用以下方法动态创建不同的服务器并从其各自的activemq客户端向连接的客户端发送消息

      1. 我创建了一个入站适配器,如下所示:

        IntegrationFlow flow;
        CustomSerializer customSerializer = getCustomSerializer(String.valueOf(hostConnection.getMaxMessageLength()),
                hostConnection.getTerminatorChar());
        
        TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
        TcpNetServerConnectionFactory cf = new TcpNetServerConnectionFactory(1234));
        cf.setSerializer(customSerializer);
        cf.setDeserializer(customSerializer);
        handler.setConnectionFactory(cf);
        
             flow = IntegrationFlows
                .from(Tcp.inboundAdapter(cf).id("adapter")).handle(handler)
                .get();
        
             this.flowContext.registration(flow).id("inflow")
             .addBean(hostConnection.getConnectionNumber(),cf)
             .addBean(hostConnection.getConnectionNumber()+"handler",handler)
             .register();
        
      2. 我创建了一个Jmsflow,其中队列中的消息发送到路由器,如下所示:

            flow = IntegrationFlows
                .from(Jms.inboundAdapter(activeMQConnectionFactory)
                .destination(hostConnection.getConnectionNumber() +"rec")) 
                .channel(directChannel()).route(new ServerRouter())
                .get(); 
        
      3. 当客户端连接到我的服务器时,我从监听器handleTcpConnectionCloseEvent(TcpConnectionOpenEvent event)创建一个流并创建一个流程:

        void createServerFlow(TcpConnectionOpenEvent event) {
            String connectionNumber = event.getConnectionFactoryName();
            TcpNetConnection server = (TcpNetConnection) event.getSource();
            TcpSendingMessageHandler handler = (TcpSendingMessageHandler) ac.getBean(connectionNumber + "handler");
        
            IntegrationFlow flow = f -> f.enrichHeaders(e -> e.header(IpHeaders.CONNECTION_ID, event.getConnectionId()))
                    .handle(handler);
            IntegrationFlowRegistration flowregister = this.flowContext.registration(flow).id("outclient").register();
        
            MessageChannel channel = flowregister.getInputChannel();
        
            this.subFlows.put(connectionNumber + "server", channel);
        }
        
      4. 我的ServerRouter找到频道并发送到目标频道

        protected Collection<MessageChannel> determineTargetChannels(Message<?> message) {
        String serverChannel = (String) message.getHeaders().get("connectionnumber");
        MessageChannel channel = HostConnectionRepository.subFlows
                .get(serverChannel+"server");
        
        return Collections.singletonList(channel);
        

        }

      5. 当我断开连接时,我从step 3中创建的flowContext中删除了流。

      6. 问题: 当我删除流时,与流关联的bean也会被删除,因为它写在相关bean的文档中也将丢弃。

        这删除我的处理程序bean,它关闭TCP适配器也是connectionfactory,因此一旦断开连接就无法连接

        如何在不丢弃处理程序bean的情况下丢弃outclientflow?

2 个答案:

答案 0 :(得分:0)

Tcp.outboundAdapter()不是TcpListener。它只是TCP套接字的发送者。这就是你得到这个例外的原因。

如果我们谈论TCP服务器,它必须是一个监听器,一个入站端点。

完全不清楚为什么要在发送操作上动态创建TCP服务器...

你需要重新思考你的逻辑并拥有这样一个TCP服务器,以便在这个动态逻辑之外进行监听。这里只使用客户端变体将TCP数据包发送到所需的TCP端口。

答案 1 :(得分:0)

目前尚不清楚你要做什么;客户端通常会启动连接,而不是为其他人提供连接的端口。

即使某人连接到该端口,客户端也不知道将消息发送到哪个套接字。所以你会在运行时遇到错误。

  

没有监听器绑定到服务器连接工厂;不会读;离开...

该消息只是说工厂没有注册组件来接收传入消息。