2
votes

I am learning about ActiveMQ, and so far I have made a simple Spring Boot producer+consumer application (call it App1 for the purposes of this question) that communicates with a local instance of ActiveMQ and everything works as expected.

Now I am trying to run a different Spring Boot application (on the same computer but after ensuring App1 is not running) that has only a consumer (no producer), but when I start up this application, the messages in the queue (that I put using a modified App1 in which I removed the consumer portion of the application) do not get picked up. In App1, as soon as the message was published, the consumer printed out the system.out print statement, but not so in this consumer-only application. Below is my listener component class:

package com.demo.listener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class Consumer {

    @JmsListener(destination = "testqueue")
    public void consume(String message) {

        System.out.println("Picked up message: " + message);

    }
}

What changes would I need to make in order achieve the desired behavior?

App1 application.properties file:

spring.activemq.in-memory=false
spring.activemq.pool.enabled=false
server.port=9000
activemq.broker-url=tcp://localhost:61616
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
security.basic.enabled=false
management.security.enabled=false

App1 JmsConfig class

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;

@Configuration
public class JmsConfig {

    @Value("${activemq.broker-url}")
    private String brokerUrl;

    @Bean
    public Queue queue() {
        return new ActiveMQQueue("testqueue");
    }

    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory() {

        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
        factory.setBrokerURL(brokerUrl);
        return factory;
    }

    @Bean
    public JmsTemplate jmsTemplate() {
        return  new JmsTemplate(activeMQConnectionFactory());
    }

}

App1 Producer class

import javax.jms.Queue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/rest/publish")
public class ProducerResource {

    @Autowired
    JmsTemplate jmsTemplate;

    @Autowired
    Queue queue;

    @GetMapping("/{message}")
    public String publishMessage(@PathVariable("message") final String message) {

        jmsTemplate.convertAndSend(queue, message);

        return "Published successfully";
    }

}

App1 consumer class is the same class I used in the consumer only application (listed above).

1
Please post your application.properties file as well, if possible for both apps. And listener configuration class code as well. You have provided too little information to find out the root cause.Amith Kumar
@AmithKumar I have added the App1 properties file. For the second app (consumer only application) that is my only JMS related class and no MQ/JMS settings are present in the properties file.ITWorker
If you use Spring-Boot you do not need Configuration bean for simple use cases like yours.рüффп
Note also the activemq url property should be prefixed by spring. like this: spring.activemq.broker-url=tcp://192.168.1.210:9876рüффп

1 Answers

2
votes

For your consumer app, you do need to add Pool connection factory & JMS message listener factory for your consumer JMStemplate to start receiving messages.

@Configuration
@EnableJms
public class ConsumerConfig {

  @Value("${activemqbrokerurl}")
  private String brokerUrl;

  @Bean
  public ActiveMQConnectionFactory activeMQConnectionFactory() {
    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL(brokerUrl);
    return activeMQConnectionFactory;
  }

  @Bean
  public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(activeMQConnectionFactory());
    factory.setConcurrency("{#setDesiredConcurrency}");
    return factory;
  }
}

Spring's MessagListenerContainer should be used for message consumption. This provides all the power of MDBs - efficient JMS consumption and pooling of the message listeners - but without requiring a full EJB container.

You can use the activemq-pool org.apache.activemq.pool.PooledConnectionFactory for efficient pooling of the connections and sessions for your collection of consumers, or you can use the Spring JMS org.springframework.jms.connection.CachingConnectionFactory to achieve the same effect.

You can read more about it here