Search code examples
springspring-amqpspring-rabbit

spring-amqp clean up resources on listener container shutdown


I have multiple message containers with one listener each.

Each listener

  1. Is not thread-safe
  2. Is declared @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
  3. Is not stateless. it has an internal buffer of processed messages
  4. Every X messages received it flushes the buffer to disk

Writing to this type of disk is very expensive and the only way to achieve the desired throughput is to only flush the buffer every X messages.

Each listener writes to their own files so that there is no need for locking.

I want to flush the buffers when the spring container is shutdown.

Each listener implements DisposableBean and a destroy() method to flush the buffer.

After some research I found out that since the beans are declared as scope prototype, the destroy method will never be called by spring because it stops managing the bean after its creation.

How can I cleanup the remaining messages in the buffer when spring shuts down in this situation?

Is there a hook in the SimpleMessageListenerContainer that I can use to call the destroy method in my listener?


Solution

  • Figured out it myself. Just had to create a custom BeanPostProcessor that also implements DisposableBean.

    @Component
    public class MyListenerBeanPostProcessor implements BeanPostProcessor, DisposableBean {
        private List<MyListener> listeners = new ArrayList<ExportVisitsListenerBase>();
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof MyListener) {
                listeners.add((MyListener) bean);
            }
            return bean;
        }
    
        @Override
        public void destroy() throws Exception {
            for (MyListener listener : listeners) {
                listener.destroy();
            }
        }
    }