【问题标题】:Read without removing message from JMS queue读取而不从 JMS 队列中删除消息
【发布时间】:2017-07-05 12:03:38
【问题描述】:

如何在不从队列中删除原始消息的情况下从 WebSphere MQ 读取消息?

我有一个从 WebSphere MQ 读取消息的 spring 应用程序。 阅读后,我有一个 process 方法,它将处理从队列中检索到的数据。

第 1 步:

response = jmsTemplate.receive();
//Message automatically removed from queue.

第 2 步:

process(response);

在 process 方法中有抛出异常的机会。如果出现异常,我需要将消息保留在队列中。

有可能吗?他们是否只有在用户确认后才能删除消息?

我尝试添加以下内容:

jmsTemplate.setSessionAcknowledgeMode(javax.jms.Session.CLIENT_ACKNOWLEDGE);

...但消息仍然被删除。

JmsTemplate创建代码sn-p:

JndiConnectionFactorySupport connectionFactoryBean = new JndiConnectionFactorySupport();
    connectionFactoryBean.setBindingsDir(this.bindingDir);


        connectionFactoryBean
                .setConnectionFactoryName(connectionFactoryName);
        connectionFactoryBean.afterPropertiesSet();
        jmsTemplate.setConnectionFactory(connectionFactoryBean.getObject());


    JndiDestinationResolver destinationResolver = new JndiDestinationResolver();
    destinationResolver.setJndiTemplate(connectionFactoryBean
            .getJndiTemplate());

    jmsTemplate.setDestinationResolver(destinationResolver);
    jmsTemplate.setReceiveTimeout(20000);
    jmsTemplate.setDefaultDestinationName(this.defaultDestinationName);

            

试过jmsTemplate.execute()方法如下:

@SuppressWarnings({ "unused", "unchecked" })
        Message responseMessage = (Message) jmsTemplate.execute(
            new SessionCallback() { 
                public Object doInJms(Session session)
                        throws JMSException {
                    MessageConsumer consumer = session
                    .createConsumer(jmsTemplate.getDestinationResolver().resolveDestinationName(session, "QUEUE_NAME", false));
                    Message response = consumer.receive(1);
                    try {
                        testMethod();//this method will throw exception.
                        response.acknowledge();
                        consumer.close();
                    } catch(Exception e){
                        consumer.close();//control will come here.
                    }
                    
                    return response;
                }
        }, true);

【问题讨论】:

    标签: java spring message-queue spring-jms


    【解决方案1】:

    您不能使用 receive() 方法执行此操作,因为当接收方法返回时操作已完成(从会话的角度来看)。

    您需要在会话范围内运行可能失败的代码;例如带有JmsTemplate.execute() 带有SessionCallback - 像这样......

    this.jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    this.jmsTemplate.convertAndSend("foo", "bar");
    try {
        String value = this.jmsTemplate.execute(session -> {
            MessageConsumer consumer = session.createConsumer(
                    this.jmsTemplate.getDestinationResolver().resolveDestinationName(session, "foo", false));
            String result;
            try {
                Message received = consumer.receive(5000);
                result = (String) this.jmsTemplate.getMessageConverter().fromMessage(received);
                // Do some stuff that might throw an exception
                received.acknowledge();
            }
            finally {
                consumer.close();
            }
            return result;
        }, true);
        System.out.println(value);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    

    【讨论】:

    • 尝试了 execute() 方法。 (代码 sn-p 添加有问题)。有用!!!非常感谢加里·拉塞尔..!!!
    【解决方案2】:

    您可以添加 JMS 消息的事务处理。见the example

    您的听众应该是"transacted"。像这样

    <jms:listener-container connection-factory="connectionFactory" acknowledge="transacted">
        <jms:listener ref="notificationProcessor" destination="incoming.queue"/>
    </jms:listener-container>
    

    【讨论】:

    • 我没有使用 JMS 配置 xml。相反,JmsTemplate 对象是使用 java 创建的。 (代码 sn-p 添加有问题)
    【解决方案3】:

    您必须浏览队列。

    使用 Websphere MQ 执行的真实代码示例

    public void browseMessagesAndJiraCreation(String jiraUserName, String jiraPassword) {
    
        int counterMessages = jmsTemplate.browse(destinationQueueName, new BrowserCallback<Integer>() {
    
            @Override
            public Integer doInJms(final Session session, final QueueBrowser queueBrowser) throws JMSException {
                Enumeration<TextMessage> enumeration = queueBrowser.getEnumeration();
                int counterMessages = 0;
                while (enumeration.hasMoreElements()) {
                    counterMessages += 1;
                    TextMessage msg = enumeration.nextElement();
                    logger.info("Found : {}", msg.getText());
                    JiraId jiraId = jiraManager.createIssue(jiraUserName, jiraPassword);
                    jiraManager.attachFileToJira(jiraId, msg.getText(), jiraUserName, jiraPassword);
                }
                return counterMessages;
            }
        });
        logger.info("{}:messages were browsed and processed from queue:{}.", counterMessages, destinationQueueName);
    }
    

    解释:

    • Spring框架JmsTemplate的使用
    • 您传递字符串 gestinationQueueName(例如 destinationQueueName=QL.PREFCNTR.USER.REPLY)
    • 文本消息的 Java 枚举
    • counterMessages 是已处理消息的计数器
    • 消息未被消费!

    【讨论】:

      猜你喜欢
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      相关资源
      最近更新 更多