带有 netty TCP 的 JMS 侦听器

JMS listener with netty TCP

我正在尝试使用 TCP 开发 Netty。我正在使用 IBM MQ 客户端连接到 MQ 代理,我的想法是我需要开发一个 TCP 服务器来接收消息并将其传递给 MQ,如果服务器响应,则将其发送给发送请求的客户端。因此,我需要为异步消息实现一个 JMS 侦听器。问题是 JMS 侦听器在 Netty 通道之外,我试图弄清楚如何读取消息将其添加到 Netty 通道并立即将其发送到连接到 TCP 套接字的客户端。我可以完美地发送消息。问题是服务器何时响应。我收到消息,从 clientConnectionProvider 和我 writeAndFlush 获得 context/channel,但我没有看到消息到达客户端。

我在主 class 中创建监听器。

public class Main {

    private final Integer port;

    private final Destination sendDestination;
    private final JMSContext jmsSendContext;

    private final JMSConsumer consumer;
    private final JMSContext jmsRecieveContext;
    private final Destination consumerDestination;

    private final ClientConnectionProvider clientConnectionProvider;

    public Main(Properties properties)
            throws JMSException {
        
            if (properties.containsKey(ConfigurationEnum.SERVER_PORT) {
                this.port = properties.getProperty(ConfigurationEnum.SERVER_PORT)
            } else {
                log.error("server.port not defined in properties"
                throw new ConfigException(
                        String.format("server.port not defined in properties");
            }

        JmsFactoryFactory ff = JmsFactoryFactory.getInstance(JmsConstants.WMQ_PROVIDER);
        JmsConnectionFactory cf = ff.createConnectionFactory();

        // Set the properties
        cf.setStringProperty(CommonConstants.WMQ_HOST_NAME,
                properties.getProperty(ConfigurationEnum.IBM_MQ_HOST.getValue()));
        cf.setIntProperty(CommonConstants.WMQ_PORT,
                Integer.parseInt(properties.getProperty(ConfigurationEnum.IBM_MQ_PORT.getValue())));
        cf.setStringProperty(CommonConstants.WMQ_CHANNEL,
                properties.getProperty(ConfigurationEnum.IBM_MQ_CHANNEL.getValue()));
        cf.setIntProperty(CommonConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
        cf.setStringProperty(CommonConstants.WMQ_QUEUE_MANAGER,
                properties.getProperty(ConfigurationEnum.IBM_QUEUE_MANAGER.getValue()));
        cf.setStringProperty(CommonConstants.WMQ_APPLICATIONNAME, "FIX Orchestra Gateway");
        cf.setBooleanProperty(JmsConstants.USER_AUTHENTICATION_MQCSP, true);
        cf.setStringProperty(JmsConstants.USERID, properties.getProperty(ConfigurationEnum.IBM_APP_USER.getValue()));
        cf.setStringProperty(JmsConstants.PASSWORD, properties.getProperty(ConfigurationEnum.IBM_APP_PASS.getValue()));

        clientConnectionProvider = new ClientConnectionProvider();
        
        jmsRecieveContext = cf.createContext();
        consumerDestination = jmsRecieveContext
                .createQueue(properties.getProperty(ConfigurationEnum.IBM_QUEUE_CONSUMER.getValue()));
        consumer = jmsRecieveContext.createConsumer(consumerDestination);
        consumer.setMessageListener(new JMSMessageListener(clientConnectionProvider));
        jmsRecieveContext.start();

        jmsSendContext = cf.createContext();
        sendDestination = jmsSendContext
                .createQueue(properties.getProperty(ConfigurationEnum.IBM_QUEUE_TRANSACTION.getValue()));

    }

public void start() throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(10);

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100).option(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new DefaultChannelInitializer());

            // Start the server.
            ChannelFuture f = serverBootstrap.bind(port).sync();

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            jmsRecieveContext.stop();
            jmsRecieveContext.close();
            jmsSendContext.close();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        Properties properties = new Properties();

        try (InputStream inputStream = new FileInputStream(args[0])) {
            properties.load(inputStream);

            new Main(properties).start();

        } catch (FileNotFoundException e) {
            log.error("Properties file specified in path {} was not found.", args[0], e);
        } catch (IOException e) {
            log.error("There was an IO error.", e);
        } catch (JMSException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ConfigException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

监听器很简单class。

@AllArgsConstructor
public class JMSMessageListener implements MessageListener {

    private final ClientConnectionProvider clientConnectionProvider;

    @Override
    public void onMessage(Message message) {

        try {
            String messageString = message.getBody(String.class);

            if (clientConnectionProvider.contains(ClientID.get(messageString))) {
                ClientConnection cc = clientConnectionProvider.getConnection(ClientID.get(messageString));
                if (cc.getCtx() == null) {
                    // TODO: Need to save message when client reconects
                } else {
                    cc.getCtx().channel().write(messageString);
                }
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

您应该调用 writeAndFlush(...) 并将 ChannelFutureListener 附加到返回给它的 ChannelFuture。在侦听器中,您可以检查写入是否成功或失败(如果成功则打印异常)。在您当前的代码中,您只调用 write(...) ,它只将消息放入 Channel 的出站缓冲区,但实际上并未将其刷新到套接字。