简体   繁体   中英

How to change the port used by tcp-ibound-gateway on the fly

Is there a way to change port used by tcp-inbound gateway on the fly? I'd like to set port and timeout used by tcp-inbound-gateway based on the configuration persisted in the database and have ability to change them on the fly without restarting an application. In order to do so I decided to use "publish-subscriber" pattern and extended TcpInboundGateway class:

public class RuntimeInboundGateway extends TcpInboundGateway implements SettingsSubscriber {

    @Autowired
    private Settings settings;

    @PostConstruct
    public void subscribe() {
        settings.subscribe(this);
    }

    @Override
    public void onSettingsChanged(Settings settings) {
        this.stop();
        AbstractByteArraySerializer serializer = new ByteArrayLfSerializer();
        TcpNetServerConnectionFactory connectionFactory = new TcpNetServerConnectionFactory(settings.getPort());
        connectionFactory.setSerializer(serializer);
        connectionFactory.afterPropertiesSet();
        this.setConnectionFactory(connectionFactory);
        this.afterPropertiesSet();
        this.start();
    }
}

The settings object is a singleton bean and when it is changed the tcp inbound gateway starts indeed listening on the new port but looks like it doesn't send inbound messages further on the flow. Here is an excerpt from xml configuration:

<int-ip:tcp-connection-factory id="connFactory" type="server" port="${port}"
                                   serializer="serializer"
                                   deserializer="serializer"/>

    <bean id="serializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer"/>

    <bean id="inboundGateway" class="com.example.RuntimeInboundGateway">
        <property name="connectionFactory" ref="connFactory"/>
        <property name="requestChannel" ref="requestChannel"/>
        <property name="replyChannel" ref="responseChannel"/>
        <property name="errorChannel" ref="exceptionChannel"/>
        <property name="autoStartup" value="true"/>
    </bean>

There is logging-channel-adapter in the configuration which logs any requests to the service without any issues until the settings are changed. After that, it doesn't and I see no messages received though I'm able to connect to the new port by the telnet localhost <NEW_PORT> . Could somebody take a look and say how the desired behaviour can be achieved?

A quick look at your code indicated it should work ok, so I just wrote a quick Spring Boot app and it worked fine for me...

@SpringBootApplication
public class So40084223Application {

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = SpringApplication.run(So40084223Application.class, args);
        Socket socket = SocketFactory.getDefault().createSocket("localhost", 1234);
        socket.getOutputStream().write("foo\r\n".getBytes());
        socket.close();
        QueueChannel queue = ctx.getBean("queue", QueueChannel.class);
        System.out.println(queue.receive(10000));
        ctx.getBean(MyInboundGateway.class).recycle(1235);
        socket = SocketFactory.getDefault().createSocket("localhost", 1235);
        socket.getOutputStream().write("fooo\r\n".getBytes());
        socket.close();
        System.out.println(queue.receive(10000));
        ctx.close();
    }

    @Bean
    public TcpNetServerConnectionFactory cf() {
        return new TcpNetServerConnectionFactory(1234);
    }

    @Bean
    public MyInboundGateway gate(TcpNetServerConnectionFactory cf) {
        MyInboundGateway gate = new MyInboundGateway();
        gate.setConnectionFactory(cf);
        gate.setRequestChannel(queue());
        return gate;
    }

    @Bean
    public QueueChannel queue() {
        return new QueueChannel();
    }

    public static class MyInboundGateway extends TcpInboundGateway implements ApplicationEventPublisherAware {

        private ApplicationEventPublisher applicationEventPublisher;

        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
            this.applicationEventPublisher = applicationEventPublisher;
        }

        public void recycle(int port) {
            stop();
            TcpNetServerConnectionFactory sf = new TcpNetServerConnectionFactory(port);
            sf.setApplicationEventPublisher(this.applicationEventPublisher);
            sf.afterPropertiesSet();
            setConnectionFactory(sf);
            afterPropertiesSet();
            start();
        }

    }

}

I would turn on DEBUG logging to see if it gives you any clues.

You also might to want to explore using the new DSL dynamic flow registration instead. The tcp-dynamic-client shows how to use that technique to add/remove flow snippets on the fly. It's on the client side, but similar techniques can be used on the server side to register/unregister your gateway and connection factory.

The cause of the troubles is me. Since the deserializer is not specified in the code above the default one is used and it couldn't demarcate inbound messages from the input byte stream. Just one line connectionFactory.setDeserializer(serializer); solved the issue I spent a day on.

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