简体   繁体   中英

Spring integration on reconnect TCP send handshake

I'm trying to use the ClientMode on the TcpSendingMessageHandler to auto-reconnect the connection. This connection needs to be kept open so it's important to implement a reconnect function.

private MessageChannel createNewSubflow(Message<?> message) {
        String host = (String) message.getHeaders().get("host");
        Integer port = (Integer) message.getHeaders().get("port");
        Assert.state(host != null && port != null, "host and/or port header missing");
        String hostPort = host + port;

        TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory(host, port);
        TcpReceivingChannelAdapter messageHandler = new TcpReceivingChannelAdapter();
        cf.setLeaveOpen(true);
        TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();

        HelloWorldInterceptorFactory factory = new HelloWorldInterceptorFactory();
        fc.setInterceptors(new TcpConnectionInterceptorFactory[] { factory} );

        cf.setInterceptorFactoryChain(fc);
        cf.setDeserializer(new CustomSerializerDeserializer());
        messageHandler.setErrorChannel(errorChannel);
        messageHandler.setConnectionFactory(cf);
        messageHandler.setOutputChannel(outputChannel);
        TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
        handler.setConnectionFactory(cf);
        handler.setClientMode(true);
        handler.setRetryInterval(5000);
        IntegrationFlow flow = f -> f.handle(handler);
        IntegrationFlowContext.IntegrationFlowRegistration flowRegistration =
                this.flowContext
                        .registration(flow)
                        .addBean(cf)
                        .id(hostPort + ".flow")
                        .register();
        MessageChannel inputChannel = flowRegistration.getInputChannel();
        this.subFlows.put(hostPort, inputChannel);
        return inputChannel;
    }

Unfortinily I need to send a handshake after the connection socket has been opened.

I tried to add a Message interceptor described in this post ( Interceptor ) but when the connection socket is restored it doesn't enter the interceptor.

I get this warning when the socket is restored:

HelloWorldInterceptor        : No publisher available to publish TcpConnectionOpenEvent [source=HelloWorldInterceptor

The warning is coming out of the interceptor because the factory was not initialized properly.

You need to add .addBean() for the interceptor factory too.

EDIT

As mentioned in the comments an alternative to the interceptors is just to use an event listener.

I just tested with this and see no problems:

@SpringBootApplication
public class So65899947Application {

    public static void main(String[] args) {
        SpringApplication.run(So65899947Application.class, args);
    }

    @Bean
    public IntegrationFlow flow() {
        return f -> f.handle(Tcp.outboundAdapter(Tcp.netClient("localhost", 1234))
                .clientMode(true)
                .retryInterval(5000));
    }

}

@Component
class InitialSender {

    private final IntegrationFlow flow;

    InitialSender(IntegrationFlow flow) {
        this.flow = flow;
    }

    @EventListener
    public void opened(TcpConnectionOpenEvent event) {
        this.flow.getInputChannel().send(new GenericMessage<>("Hello there", 
                Collections.singletonMap(IpHeaders.CONNECTION_ID, event.getConnectionId())));
    }

}
$ nc -l 1234
Hello there
^C

$ nc -l 1234
Hello there
^C

$ nc -l 1234
Hello there
^C

$ nc -l 1234
Hello there
^C

$ nc -l 1234
Hello there
^C

EDIT2

Same results for me when I changed it to use a gateway...

@SpringBootApplication
@IntegrationComponentScan
public class So65899947Application {

    public static void main(String[] args) {
        SpringApplication.run(So65899947Application.class, args);
    }

    @Bean
    public IntegrationFlow flow() {
        return f -> f.handle(Tcp.outboundAdapter(Tcp.netClient("localhost", 1234))
                .clientMode(true)
                .retryInterval(5000));
    }

}

@MessagingGateway(defaultRequestChannel = "flow.input")
interface Gate {

    void handShake(@Payload String message, @Header(IpHeaders.CONNECTION_ID) String conn);

}

@Component
class InitialSender {

    private final Gate gate;

    InitialSender(Gate gate) {
        this.gate = gate;
    }

    @EventListener
    public void opened(TcpConnectionOpenEvent event) {
        this.gate.handShake("Hello there", event.getConnectionId());
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM