如何动态更改tcp-ibound-gateway使用的端口

时间:2016-10-17 10:38:41

标签: java spring-integration

有没有办法在运行中更改tcp-inbound网关使用的端口?我想根据数据库中保留的配置设置tcp-inbound-gateway使用的端口和超时,并且能够在不重新启动应用程序的情况下动态更改它们。为此,我决定使用“publish-subscriber”模式和扩展TcpInboundGateway类:

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();
    }
}

settings对象是一个单例bean,当它被更改时,tcp入站网关开始实际上正在侦听新端口,但看起来它不会在流上进一步发送入站消息。以下是xml配置的摘录:

<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>

配置中有logging-channel-adapter,可以在更改设置之前将任何请求记录到服务中而不会出现任何问题。之后,它没有,我看到虽然我能够通过telnet localhost <NEW_PORT>连接到新端口但没有收到任何消息。有人可以看看如何实现理想的行为吗?

2 个答案:

答案 0 :(得分:0)

快速查看代码表明它应该可以正常工作,所以我只是编写了一个快速的Spring Boot应用程序,它对我来说很好......

@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();
        }

    }

}

我会打开DEBUG日志记录,看看它是否能为您提供任何线索。

您也可能想要使用新的DSL dynamic flow registration进行探索。 tcp-dynamic-client显示了如何使用该技术动态添加/删除流片段。它位于客户端,但可以在服务器端使用类似的技术来注册/取消注册您的网关和连接工厂。

答案 1 :(得分:0)

麻烦的原因是我。由于未在上面的代码中指定解串器,因此使用了默认解串器,并且它无法从输入字节流中划分入站消息。只有一行connectionFactory.setDeserializer(serializer);解决了我花了一天时间的问题。