Auto-detect JMS sessionTransacted flag
If a JtaTransactionManager is present, it is associated with the auto-created JmsListenerContainerFactory. However, if no such transaction manager is present, local transaction support is not enabled. This gives a default situation where the message is acknowledged even before the listener is invoked. We now make sure to turn on local JMS transactions if no JtaTransactionManager is present. Fixes gh-3393
This commit is contained in:
		
							parent
							
								
									f4c95eafc2
								
							
						
					
					
						commit
						441049cf4e
					
				| 
						 | 
					@ -61,6 +61,9 @@ class JmsAnnotationDrivenConfiguration {
 | 
				
			||||||
		if (this.transactionManager != null) {
 | 
							if (this.transactionManager != null) {
 | 
				
			||||||
			factory.setTransactionManager(this.transactionManager);
 | 
								factory.setTransactionManager(this.transactionManager);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								factory.setSessionTransacted(true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (this.destinationResolver != null) {
 | 
							if (this.destinationResolver != null) {
 | 
				
			||||||
			factory.setDestinationResolver(this.destinationResolver);
 | 
								factory.setDestinationResolver(this.destinationResolver);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,12 +23,14 @@ import org.apache.activemq.pool.PooledConnectionFactory;
 | 
				
			||||||
import org.junit.After;
 | 
					import org.junit.After;
 | 
				
			||||||
import org.junit.Test;
 | 
					import org.junit.Test;
 | 
				
			||||||
import org.springframework.beans.BeansException;
 | 
					import org.springframework.beans.BeansException;
 | 
				
			||||||
 | 
					import org.springframework.beans.DirectFieldAccessor;
 | 
				
			||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
 | 
					import org.springframework.beans.factory.config.BeanPostProcessor;
 | 
				
			||||||
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
 | 
					import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
 | 
				
			||||||
import org.springframework.boot.test.EnvironmentTestUtils;
 | 
					import org.springframework.boot.test.EnvironmentTestUtils;
 | 
				
			||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 | 
					import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					import org.springframework.jdbc.datasource.DataSourceTransactionManager;
 | 
				
			||||||
import org.springframework.jms.annotation.EnableJms;
 | 
					import org.springframework.jms.annotation.EnableJms;
 | 
				
			||||||
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
 | 
					import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
 | 
				
			||||||
import org.springframework.jms.config.JmsListenerConfigUtils;
 | 
					import org.springframework.jms.config.JmsListenerConfigUtils;
 | 
				
			||||||
| 
						 | 
					@ -38,10 +40,13 @@ import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
 | 
				
			||||||
import org.springframework.jms.core.JmsMessagingTemplate;
 | 
					import org.springframework.jms.core.JmsMessagingTemplate;
 | 
				
			||||||
import org.springframework.jms.core.JmsTemplate;
 | 
					import org.springframework.jms.core.JmsTemplate;
 | 
				
			||||||
import org.springframework.jms.listener.DefaultMessageListenerContainer;
 | 
					import org.springframework.jms.listener.DefaultMessageListenerContainer;
 | 
				
			||||||
 | 
					import org.springframework.transaction.jta.JtaTransactionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.junit.Assert.assertEquals;
 | 
					import static org.junit.Assert.assertEquals;
 | 
				
			||||||
import static org.junit.Assert.assertFalse;
 | 
					import static org.junit.Assert.assertFalse;
 | 
				
			||||||
import static org.junit.Assert.assertNotNull;
 | 
					import static org.junit.Assert.assertNotNull;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertNull;
 | 
				
			||||||
 | 
					import static org.junit.Assert.assertSame;
 | 
				
			||||||
import static org.junit.Assert.assertTrue;
 | 
					import static org.junit.Assert.assertTrue;
 | 
				
			||||||
import static org.mockito.Mockito.mock;
 | 
					import static org.mockito.Mockito.mock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -137,6 +142,48 @@ public class JmsAutoConfigurationTests {
 | 
				
			||||||
				jmsListenerContainerFactory.getClass());
 | 
									jmsListenerContainerFactory.getClass());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void testDefaultContainerFactoryWithJtaTransactionManager() {
 | 
				
			||||||
 | 
							this.context = createContext(TestConfiguration7.class,
 | 
				
			||||||
 | 
									EnableJmsConfiguration.class);
 | 
				
			||||||
 | 
							JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
 | 
				
			||||||
 | 
									.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
 | 
				
			||||||
 | 
							assertEquals(DefaultJmsListenerContainerFactory.class,
 | 
				
			||||||
 | 
									jmsListenerContainerFactory.getClass());
 | 
				
			||||||
 | 
							DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
 | 
				
			||||||
 | 
									jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
 | 
				
			||||||
 | 
							assertFalse("wrong session transacted flag with JTA transactions", listenerContainer.isSessionTransacted());
 | 
				
			||||||
 | 
							assertSame(this.context.getBean(JtaTransactionManager.class),
 | 
				
			||||||
 | 
									new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void testDefaultContainerFactoryNonJtaTransactionManager() {
 | 
				
			||||||
 | 
							this.context = createContext(TestConfiguration8.class,
 | 
				
			||||||
 | 
									EnableJmsConfiguration.class);
 | 
				
			||||||
 | 
							JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
 | 
				
			||||||
 | 
									.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
 | 
				
			||||||
 | 
							assertEquals(DefaultJmsListenerContainerFactory.class,
 | 
				
			||||||
 | 
									jmsListenerContainerFactory.getClass());
 | 
				
			||||||
 | 
							DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
 | 
				
			||||||
 | 
									jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
 | 
				
			||||||
 | 
							assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
 | 
				
			||||||
 | 
							assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void testDefaultContainerFactoryNoTransactionManager() {
 | 
				
			||||||
 | 
							this.context = createContext(EnableJmsConfiguration.class);
 | 
				
			||||||
 | 
							JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
 | 
				
			||||||
 | 
									.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
 | 
				
			||||||
 | 
							assertEquals(DefaultJmsListenerContainerFactory.class,
 | 
				
			||||||
 | 
									jmsListenerContainerFactory.getClass());
 | 
				
			||||||
 | 
							DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
 | 
				
			||||||
 | 
									jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
 | 
				
			||||||
 | 
							assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
 | 
				
			||||||
 | 
							assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testPubSubDisabledByDefault() {
 | 
						public void testPubSubDisabledByDefault() {
 | 
				
			||||||
		load(TestConfiguration.class);
 | 
							load(TestConfiguration.class);
 | 
				
			||||||
| 
						 | 
					@ -350,6 +397,26 @@ public class JmsAutoConfigurationTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Configuration
 | 
				
			||||||
 | 
						protected static class TestConfiguration7 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Bean
 | 
				
			||||||
 | 
							JtaTransactionManager transactionManager() {
 | 
				
			||||||
 | 
								return mock(JtaTransactionManager.class);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Configuration
 | 
				
			||||||
 | 
						protected static class TestConfiguration8 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Bean
 | 
				
			||||||
 | 
							DataSourceTransactionManager transactionManager() {
 | 
				
			||||||
 | 
								return mock(DataSourceTransactionManager.class);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Configuration
 | 
						@Configuration
 | 
				
			||||||
	@EnableJms
 | 
						@EnableJms
 | 
				
			||||||
	protected static class EnableJmsConfiguration {
 | 
						protected static class EnableJmsConfiguration {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue