简体   繁体   中英

Spring Boot + ActiveMQ programmatically subscribe to topics on the fly

I am trying to implement a functionality where a listener class I have can subscribe/unsubscribe to JMS topics. After some research there doesn't see to be a clear way to do this and I've come up with two solutions:

  1. Have a listener class which holds a list of String topic names and periodically run through all these topics its supposed to be subscribed to and run the blocking jmsTemplate.receiveAndConvert(topicName) on each (probably delegating the blocking operation itself to a worker pool). Subscribing/Unsubscribing from a topic would be as simple as removing a topic name from the list.
  2. Have a factory class which would build a new listener for each topic the application needs to subscribe to, using a method like:

     public MessageListenerContainer createListener(String topic) { DefaultMessageListenerContainer container = new DefaultMessageListenerContainer(); container.setConnectionFactory(connectionFactory()); container.setDestinationName(topic); container.setMessageListener(new MyListenerClass()); return container;

    }

The second option seems more elegant to me, but I am unsure of the lifecycle of the listeners. I went through a bit of the source for spring boot's jms and activemq modules and noticed that DefaultMessageListenerContainer has methods initialize() and start() though I'm unsure how/if I need to use these, as the only way I could find a MessageListenerContainer being built this way is as a Bean declaration. Also when unsubscribing from a topic, therefore wanting to destroy the listener container associated with it, is there more that needs to be done except calling the stop(callback) method?

Is my understanding of JMS/ActiveMQ and its Spring integration correct in that there is no simpler way to achieve this? Is my approach correct?

IMHO as long as you

  • obtain the connectionFactory from spring ( not a PooledConnectionFactory one)
  • properly call initialise() and start() on subscription and stop() to unsuscribe
  • do not expect message redelivery in case of exception

everything should be fine with the second approach

To register new JmsListenerEndpoint in runtime you must complete 2 steps

1 Create custom MessageListener service

@Service
public class CustomMessageListener implements MessageListener {
    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println("[Custom message listener] " + textMessage.getText());
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

2 Register new endpoint, using JmsListenerEndpointRegistry

@Service
public class MessageListenersService {
    @Autowired
    private JmsListenerEndpointRegistry registry;

    @Autowired
    @Qualifier("containerFactory")
    private DefaultJmsListenerContainerFactory factory;

    public void registerListener(String queueNameToListen, MessageListener listener) {
        SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
        endpoint.setId("ep-"+listener.hashCode()); // ID is mandatory
        endpoint.setMessageListener(listener);
        endpoint.setDestination(queueNameToListen);
        registry.registerListenerContainer(endpoint, factory, true);
    }
}

Use it

    private static final String CUSTOM_DESTINATION = "queue-42";

    @Autowired
    MessageListenersService messageListenersService;
    @Autowired
    CustomMessageListener customMessageListener;
    @Autowired
    JmsTemplate jmsTemplate;

    @PostConstruct
    public void createCustomListener() throws InterruptedException {
        messageListenersService.registerListener(CUSTOM_DESTINATION, customMessageListener);
        jmsTemplate.send(CUSTOM_DESTINATION, session -> session.createTextMessage("hello world"));

        // wait your message:
        TimeUnit.SECONDS.sleep(1);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM