简体   繁体   中英

Stop a spring jms message listener

I have a scenario where i need to stop the spring's DefaultMessageListenerContainer and then later start that again. I have 10 different DefaultMessageListenerContainer listening to 10 different queue. All 10 different containers are calling the same method of same message listener class. Now i want to stop the messagelistenercontainer for a particular queue depending on the exception i get in onMessage method. Please suggest me how i can achieve the above scenario.

Below is my listener configuration

<bean id="msglistenerForAuditError" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="jmsFactory"/>
        <property name="sessionTransacted" value="true"/>
        <property name="destinationName" value="test.audit.error2"/>
        <property name="messageListener" ref="auditerrorListener" />
    </bean>

    <bean id="msglistenerForAuditEvent" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="jmsFactory"/>
        <property name="sessionTransacted" value="true"/>
        <property name="destinationName" value="test.audit.event2"/>
        <property name="messageListener" ref="auditerrorListener" />
    </bean>

The DefaultMessageListenerContainer is a lifecycle bean and as such it exposes a start and a stop method that you can use to start and stop the listener, respectively.

You can build a service on your own that is gathering all known instances in the context and you can then loop over those to stop the containers, something like

@Service
public class MyService {

    private final Collection<DefaultMessageListenerContainer> containers;

    @Autowired
    public MyService(Collection<DefaultMessageListenerContainer> containers) {
        this.containers = containers;
    }

    public void stopAll() {
        // iterate over the collection and call "stop()" on each item
    }
}

That being said:

  1. You should not invoke this service as part of a message listener as attempting to stop the container while the thread is processing a message will have weird side effect
  2. The whole use case looks suspicious to me. Your message listeners should be resilient and, more importantly, they should be independent of each other; if you are stopping listener A because listener B threw an exception, something is definitely wrong in your design

stop method on DefaultMessageListenerContainer did not worked but shutdown method worked perfectly.

 for(DefaultMessageListenerContainer defaultCont:containers){
         defaultCont.shutdown();
      }

Injecting a collection of DefaultMessageListenerContainer did not work for me, I use Spring Boot 1.4.x, with Spring 4.3.x

Here's how I solved it:

package org.example.queue;

import org.springframework.jms.config.JmsListenerEndpointRegistry;
//import other stuffs

@Component
public class QueueManager {


   @Autowired
   JmsListenerEndpointRegistry endpointRegistry;


    public void shutdown() {
        endpointRegistry.getListenerContainers().forEach((container) -> {
            if (container.isRunning()) {
                log.debug("Shutting down listener: " + container.getClass().getName());
                container.stop();
            }
        });
    }

    public void start() {
        endpointRegistry.getListenerContainers().forEach((container) -> {
            if (!container.isRunning()) {
                log.debug("Starting listener: " + container.getClass().getName());
                container.start();
            }
        });
    }

}

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