如何在Spring Boot中从ActiveMQ队列中读取待处理消息

时间:2018-04-13 12:19:09

标签: spring-boot jms activemq spring-jms

我喜欢使用Spring启动读取ActiveMQ队列中的挂起(未确认)消息。怎么做?

到目前为止,我可以在发送到队列时读取消息:

@JmsListener(destination = "LOCAL.TEST", 
  containerFactory = "myJmsListenerContainerFactory")
public void receiveMessage(final Message jsonMessage) throws JMSException {
    String messageData = null;
    // jsonMessage.acknowledge(); // dont consume message (for testing)
    LOGGER.info("=== Received message {}", jsonMessage);
}

使用mq-connection的标准配置:

@Bean
public ActiveMQConnectionFactory getActiveMQConnectionFactory() {
    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(BROKER_URL + ":" + BROKER_PORT);
    return activeMQConnectionFactory;
}

和标准的ListenerContainerFactory:

@Bean
public DefaultJmsListenerContainerFactory myJmsListenerContainerFactory() {
  DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
  factory.setConnectionFactory(getActiveMQConnectionFactory());
  factory.setConcurrency("1-1");
  return factory;
}

但如果我使用

手动发送消息,则只会记录一条消息
@Autowired
private JmsTemplate jmsTemplate;

public void send(String destination, String message) {
    LOGGER.info("sending message='{}' to destination='{}'", message, destination);
    jmsTemplate.convertAndSend(destination, message);
}

使用标准模板

@Bean
public JmsTemplate jmsTemplate() {
  JmsTemplate template = new JmsTemplate();
  template.setConnectionFactory(getActiveMQConnectionFactory());
  return template;
}

我无法读取之前发送的仍在队列中的消息(因为我没有.acknowledge()他们)...

3 个答案:

答案 0 :(得分:3)

JMS supports "browsing" messages似乎是您想要的功能。因此,您应该将Spring应用程序更改为使用QueueBrowser而不是实际使用消息。

答案 1 :(得分:1)

如果未得到确认,则不会重新发送消息。在会话关闭或连接丢失之前,它们不会返回队列,例如通过停止(并重新启动)工厂创建的侦听器容器。

您可以使用JmsListenerEndpointRegistry bean访问容器(或停止/启动将停止/启动其所有容器的整个注册表)。

答案 2 :(得分:1)

要阅读所有待处理的邮件,您可以这样做

    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616?jms.redeliveryPolicy.maximumRedeliveries=1");
    Connection connection = connectionFactory.createConnection("admin", "admin");
    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    Destination destination = session.createQueue("listenerQueue");
    MessageConsumer consumer = session.createConsumer(destination);

    QueueBrowser browser = session.createBrowser((Queue) destination);
    Enumeration elems = browser.getEnumeration();
    while (elems.hasMoreElements()) {
        Message message = (Message) consumer.receive();

        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            System.out.println("Incoming Message: '" + textMessage.getText() + "'");
            message.acknowledge();
        }
    }
    connection.close();

Spring引导ActiveMQ的逐步实现。让我们编写一些代码使其更清晰。这将有助于仅读取当前会话中的所有待处理邮件。

  1. 在pom.xml文件中添加这些依赖项。
<!-- Dependencies to setup JMS and active mq environment -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
        </dependency>
  1. 将@EnableJms添加到存在main()方法的主控制器中。
  2. 仅通过在应用程序控制器中添加这两种方法来创建连接工厂。
@Bean
    public JmsListenerContainerFactory<?> myFactory(
        ConnectionFactory connectionFactory,
        DefaultJmsListenerContainerFactoryConfigurer configurer) {
      DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
      logger.info("configuring jms connection factory....");
      // anonymous class
      factory.setErrorHandler(
              new ErrorHandler() {
                  @Override
                  public void handleError(Throwable t) {
                      logger.error("An error has occurred in the transaction", t);
                  }
              });
      // lambda function
      factory.setErrorHandler(t -> logger.info("An error has occurred in the transaction"));
      configurer.configure(factory, connectionFactory);

      return factory;
    }

    // Serialize message content to json using TextMessage
    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
      MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
      converter.setTargetType(MessageType.TEXT);
      converter.setTypeIdPropertyName("_type");
      return converter;
    } 
  1. application.yml文件中的提及凭证为
spring.activemq.user=admin
spring.activemq.password=admin
spring.activemq.broker-url=tcp://localhost:61616?jms.redeliveryPolicy.maximumRedeliveries=1

  1. 在任何spring bean类中自动连接jmsTemplate。
@Autowired
private JmsTemplate jmsTemplate;
  1. 现在是时候将消息发送到队列了。
jmsTemplate.convertAndSend("anyQueueName", "value1");
jmsTemplate.convertAndSend("anyQueueName", "value2");
...
  1. 添加一个jmslistener。当任何消息被推入队列时,JMS将自动调用此方法。
@JmsListener(destination ="anyQueueName", containerFactory = "myFactory")
    public void receiveMessage(String user) {
        System.out.println("Received <" + user + ">");
    }
  1. 您可以手动阅读队列中可用的消息:-
import javax.jms.TextMessage;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;

public void readMessageFromQueue(){
jmsTemplate.browse("anyQueueName", new BrowserCallback<TextMessage>() {
            @Override
            public TextMessage doInJms(Session session, QueueBrowser browser) throws JMSException {
                Enumeration<TextMessage> messages = browser.getEnumeration();
                while (messages.hasMoreElements()) {
                    System.out.println("message found : -"+ messages.nextElement().getText());
                }
            }
        });
}

输出:-
找到消息:-value1

找到消息:-value2

-快乐编码