yogimogi
yogimogi

Reputation: 21

How to have dynamic selector with DefaultMessageListenerContainer (in spring-boot)?

I have a spring-boot application with ActiveMQ JMS. I have a queue in the application which will get messages with a string property say color. Value of color can be red, green or blue. Application has a Rest service where it will get list of color(s) { one or more } which should be used as a SELECTOR when listening for the messages on the queue. Over the lifetime of the application, this might change, so the value of SELECTOR can look like "color='red'", "color='blue' OR color='red'" or "color='green'".

@Bean
MessageListenerAdapter adapter() {        
    return new MessageListenerAdapter(new Object() {
        // message handler
    });
}
@Bean
DefaultMessageListenerContainer container(ConnectionFactory cf) throws Exception {
    DefaultMessageListenerContainer c = new DefaultMessageListenerContainer();
    c.setMessageListener(adapter());
    c.setConcurrency(this.concurrency);
    c.setMessageSelector(this.selector);
    c.setConnectionFactory(cf);
    c.setDestinationName(this.q);

    return c;
}

Was planning to use above code to achieve this; code works fine to start with initial selector, however when selector needs to change following code does not work.

c.stop();
// modify value of selector
c.setMessageSelector(this.selector);
c.start();

Looks like, I have a working solution. I put @Scope("prototype") on top of method container() and have a method which instantiates a new DefaultMessageListenerContainer whenever selector changes.

public void xx(String selector) {
    this.selector = selector;
    DefaultMessageListenerContainer c = 
        context.getBean("container", DefaultMessageListenerContainer.class);
    c.start();
}

Is this the right way to go about this? Also, when selector changes and I instantiate a new DefaultMessageListenerContainer, what's the correct way to shutdown/stop existing DefaultMessageListenerContainer?

regards, Yogi

Upvotes: 0

Views: 2328

Answers (1)

Stephane Nicoll
Stephane Nicoll

Reputation: 33091

The prototype thing looks a very bad idea to me.

MessageListenerContainer is meant to be a singleton that is responsible to handle listeners for a particular queue or topic configuration. The selector is a JMS spec so you basically need to reconfigure the listener container at runtime which will require you to fully stop the listener, change its configuration and restart it. I haven't seen your code but I don't see a reason why it wouldn't work.

Having said that, why are you using a selector for this? If the selector changes during the lifetime of your application, wouldn't it be better to actually perform that selection in your own logic? Having a selector at the JMS level is interesting if you have several message types on the same queue and you want different thread pools for them (i.e. you want 5 concurrent listeners for "red" and only 2 for green for instance). If you don't have that requirement having a generic route that filters the incoming message is probably a better idea.

If you do have that requirement, stopping the container, changing its config and restarting it should work. Unfortunately it doesn't so I've created SPR-14604 to track this issue.

Upvotes: 1

Related Questions