From 996c1cc0a6112e542ca184c8fe6ffb680b630a40 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 4 Apr 2016 18:21:10 +0200 Subject: [PATCH] Fix Auto-Startup for @JmsListener Ignore container's auto-startup once the context is refreshed. Issue: SPR-14015 --- .../config/JmsListenerEndpointRegistry.java | 32 +++++++++++--- .../jms/annotation/EnableJmsTests.java | 42 +++++++++++++++++++ .../JmsListenerContainerTestFactory.java | 9 +++- .../config/MessageListenerTestContainer.java | 10 ++++- 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java index 5ffa326c4d6..7f7c419cb6d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +26,15 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; import org.springframework.context.SmartLifecycle; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.jms.listener.MessageListenerContainer; import org.springframework.util.Assert; @@ -53,7 +58,8 @@ import org.springframework.util.Assert; * @see MessageListenerContainer * @see JmsListenerContainerFactory */ -public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecycle { +public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecycle, + ApplicationContextAware, ApplicationListener { protected final Log logger = LogFactory.getLog(getClass()); @@ -62,6 +68,15 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc private int phase = Integer.MAX_VALUE; + private ApplicationContext applicationContext; + + private boolean contextRefreshed; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + /** * Return the {@link MessageListenerContainer} with the specified id or @@ -181,6 +196,13 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc } + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if (event.getApplicationContext().equals(this.applicationContext)) { + this.contextRefreshed = true; + } + } + // Delegating implementation of SmartLifecycle @Override @@ -228,11 +250,11 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc /** * Start the specified {@link MessageListenerContainer} if it should be started - * on startup. + * on startup or when start is called explicitly after startup. * @see MessageListenerContainer#isAutoStartup() */ - private static void startIfNecessary(MessageListenerContainer listenerContainer) { - if (listenerContainer.isAutoStartup()) { + private void startIfNecessary(MessageListenerContainer listenerContainer) { + if (this.contextRefreshed || listenerContainer.isAutoStartup()) { listenerContainer.start(); } } diff --git a/spring-jms/src/test/java/org/springframework/jms/annotation/EnableJmsTests.java b/spring-jms/src/test/java/org/springframework/jms/annotation/EnableJmsTests.java index 2fc8d46e12d..d0726af9af8 100644 --- a/spring-jms/src/test/java/org/springframework/jms/annotation/EnableJmsTests.java +++ b/spring-jms/src/test/java/org/springframework/jms/annotation/EnableJmsTests.java @@ -109,6 +109,31 @@ public class EnableJmsTests extends AbstractJmsAnnotationDrivenTests { testDefaultContainerFactoryConfiguration(context); } + @Test + public void containerAreStartedByDefault() { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( + EnableJmsDefaultContainerFactoryConfig.class, DefaultBean.class); + JmsListenerContainerTestFactory factory = + context.getBean(JmsListenerContainerTestFactory.class); + MessageListenerTestContainer container = factory.getListenerContainers().get(0); + assertTrue(container.isAutoStartup()); + assertTrue(container.isStarted()); + } + + @Test + public void containerCanBeStarterViaTheRegistry() { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( + EnableJmsAutoStartupFalseConfig.class, DefaultBean.class); + JmsListenerContainerTestFactory factory = + context.getBean(JmsListenerContainerTestFactory.class); + MessageListenerTestContainer container = factory.getListenerContainers().get(0); + assertFalse(container.isAutoStartup()); + assertFalse(container.isStarted()); + JmsListenerEndpointRegistry registry = context.getBean(JmsListenerEndpointRegistry.class); + registry.start(); + assertTrue(container.isStarted()); + } + @Override @Test public void jmsHandlerMethodFactoryConfiguration() throws JMSException { @@ -314,6 +339,23 @@ public class EnableJmsTests extends AbstractJmsAnnotationDrivenTests { } } + @Configuration + @EnableJms + static class EnableJmsAutoStartupFalseConfig implements JmsListenerConfigurer { + + @Override + public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) { + registrar.setContainerFactory(simpleFactory()); + } + + @Bean + public JmsListenerContainerTestFactory simpleFactory() { + JmsListenerContainerTestFactory factory = new JmsListenerContainerTestFactory(); + factory.setAutoStartup(false); + return factory; + } + } + @Component @Lazy diff --git a/spring-jms/src/test/java/org/springframework/jms/config/JmsListenerContainerTestFactory.java b/spring-jms/src/test/java/org/springframework/jms/config/JmsListenerContainerTestFactory.java index d51e06ee635..15afc3962ac 100644 --- a/spring-jms/src/test/java/org/springframework/jms/config/JmsListenerContainerTestFactory.java +++ b/spring-jms/src/test/java/org/springframework/jms/config/JmsListenerContainerTestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,15 @@ import java.util.Map; */ public class JmsListenerContainerTestFactory implements JmsListenerContainerFactory { + private boolean autoStartup = true; + private final Map listenerContainers = new LinkedHashMap<>(); + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + public List getListenerContainers() { return new ArrayList<>(this.listenerContainers.values()); } @@ -40,6 +46,7 @@ public class JmsListenerContainerTestFactory implements JmsListenerContainerFact @Override public MessageListenerTestContainer createListenerContainer(JmsListenerEndpoint endpoint) { MessageListenerTestContainer container = new MessageListenerTestContainer(endpoint); + container.setAutoStartup(this.autoStartup); this.listenerContainers.put(endpoint.getId(), container); return container; } diff --git a/spring-jms/src/test/java/org/springframework/jms/config/MessageListenerTestContainer.java b/spring-jms/src/test/java/org/springframework/jms/config/MessageListenerTestContainer.java index 7c723b7f427..dea96feda83 100644 --- a/spring-jms/src/test/java/org/springframework/jms/config/MessageListenerTestContainer.java +++ b/spring-jms/src/test/java/org/springframework/jms/config/MessageListenerTestContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,8 @@ public class MessageListenerTestContainer private final JmsListenerEndpoint endpoint; + private boolean autoStartup = true; + private boolean startInvoked; private boolean initializationInvoked; @@ -43,6 +45,10 @@ public class MessageListenerTestContainer this.endpoint = endpoint; } + public void setAutoStartup(boolean autoStartup) { + this.autoStartup = autoStartup; + } + public JmsListenerEndpoint getEndpoint() { return endpoint; } @@ -86,7 +92,7 @@ public class MessageListenerTestContainer @Override public boolean isAutoStartup() { - return true; + return this.autoStartup; } @Override