Aitor Gonzalez
Aitor Gonzalez

Reputation: 125

Modify @JMSListener destination on-the-fly on Spring Boot

I have developed a @JMSListener that gets the destination from Java properties and works just fine.

But now I would need to be able to change the "destination" of the queue on runtime without having to reset the whole application, and even if I modify the Properties on runtime, the queue "destination" does not change.

Here is how We are implementing the @JMSListener:


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Component("b2b.CCRReceiver")
@Slf4j
public class CCRReceiver {

  //SOME_VARIABLES

    @Transactional
    @JmsListener(destination = "${tibco.configuration.queues.upsert}", containerFactory = "jmsFactory", concurrency = "${jms.concurrency}")
    public void receiveMessage(Message message) {
        //DO_SOME_STUFF
    }
}

As you can see, I get the destination from a Value Expression the first time and it works fine, but then I don't know how to access the JMSListener and change it's destination.

Can this be done? Is there any way to change the destination?

Or I will have to implement this JMS Listener in an other way that allows me to do this?

Upvotes: 0

Views: 2626

Answers (2)

Leonardo Savio
Leonardo Savio

Reputation: 431

I solve this problem work with a component Listener Thread. Using TaskExecutor and ApplicationContext to manage. You can create at runtime. I'm still working on it. I'll try Gary Russell's suggestion too. Sorry about english. Feel free to correct.

applicationContext.getBean(ExampleListenerJMS.class);
... 
taskExecutor.execute(exampleListenerJMS);

The class listener "implements Runnable, MessageListener" with a implementation getting custom connection managers (activemq servers different).

@Component
@Scope("application")
public class ExampleListenerJMS implements Runnable, MessageListener {

private EspecificManagerJMS jms = new EspecificManagerJMS();

@Override
public void run() {
    customAndChekingActions();
}

protected void customAndChekingActions() {
...
    try {
        Destination destination = jms.getSession().createQueue(queue);
        MessageConsumer consumer = jms.getSession().createConsumer(destination);
        consumer.setMessageListener(this);
        ...
    } catch (JMSException e) {
        e.printStackTrace();
        ...
    }
}

@Override
public void onMessage(Message message) {
...
}

I hope it helped you

Upvotes: 1

Gary Russell
Gary Russell

Reputation: 174554

This should work:

  • Give the listener an id property

  • Auto wire the JmsListenerEndpointRegistry (or otherwise get a reference to it)

  • registry.getListenerContainer("myListener").stop();

  • registry.getListenerContainer("myListener").shutdown();

  • ((AbstractMessageListenerContainer) registry.getListenerContainer("myListener")) .setDestinationName("newOne")

  • registry.getListenerContainer("myListener").initialize();

  • registry.getListenerContainer("myListener").start();

Upvotes: 2

Related Questions