Allow to easily customize ListenerContainerFactory
Previously, if one wants to create a custom `JmsListenerContainerFactory` or `RabbitListenerContainerFactory`, a bunch of code from the auto- configuration must be duplicated. This commit introduces two services to configure such factory for JMS and AMQP with the same sensible defaults that were applied by the auto-configufrations. Closes gh-5138
This commit is contained in:
parent
1c170b35ea
commit
b726974bca
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
|
@ -20,7 +20,6 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit;
|
|||
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
|
||||
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitProperties.Listener;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -37,30 +36,18 @@ import org.springframework.context.annotation.Configuration;
|
|||
@ConditionalOnClass(EnableRabbit.class)
|
||||
class RabbitAnnotationDrivenConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactoryConfigurer() {
|
||||
return new RabbitListenerContainerFactoryConfigurer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "rabbitListenerContainerFactory")
|
||||
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
|
||||
ConnectionFactory connectionFactory, RabbitProperties config) {
|
||||
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
Listener listenerConfig = config.getListener();
|
||||
factory.setAutoStartup(listenerConfig.isAutoStartup());
|
||||
if (listenerConfig.getAcknowledgeMode() != null) {
|
||||
factory.setAcknowledgeMode(listenerConfig.getAcknowledgeMode());
|
||||
}
|
||||
if (listenerConfig.getConcurrency() != null) {
|
||||
factory.setConcurrentConsumers(listenerConfig.getConcurrency());
|
||||
}
|
||||
if (listenerConfig.getMaxConcurrency() != null) {
|
||||
factory.setMaxConcurrentConsumers(listenerConfig.getMaxConcurrency());
|
||||
}
|
||||
if (listenerConfig.getPrefetch() != null) {
|
||||
factory.setPrefetchCount(listenerConfig.getPrefetch());
|
||||
}
|
||||
if (listenerConfig.getTransactionSize() != null) {
|
||||
factory.setTxSize(listenerConfig.getTransactionSize());
|
||||
}
|
||||
return factory;
|
||||
RabbitListenerContainerFactoryConfigurer configurer,
|
||||
ConnectionFactory connectionFactory) {
|
||||
return configurer.createRabbitListenerContainerFactory(connectionFactory);
|
||||
}
|
||||
|
||||
@EnableRabbit
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright 2012-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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.amqp;
|
||||
|
||||
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
|
||||
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
|
||||
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configure {@link RabbitListenerContainerFactory} with sensible defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.3
|
||||
*/
|
||||
public final class RabbitListenerContainerFactoryConfigurer {
|
||||
|
||||
private RabbitProperties rabbitProperties;
|
||||
|
||||
/**
|
||||
* Set the {@link RabbitProperties} to use.
|
||||
* @param rabbitProperties the {@link RabbitProperties}
|
||||
*/
|
||||
@Autowired
|
||||
public void setRabbitProperties(RabbitProperties rabbitProperties) {
|
||||
this.rabbitProperties = rabbitProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new and pre-configured {@link SimpleRabbitListenerContainerFactory} instance
|
||||
* for the specified {@link ConnectionFactory}.
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use.
|
||||
* @return a pre-configured {@link SimpleRabbitListenerContainerFactory}
|
||||
*/
|
||||
public SimpleRabbitListenerContainerFactory createRabbitListenerContainerFactory(
|
||||
ConnectionFactory connectionFactory) {
|
||||
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
|
||||
configure(factory, connectionFactory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the default settings for the specified jms listener container factory. The
|
||||
* factory can be further tuned and default settings can be overridden.
|
||||
* @param factory the {@link SimpleRabbitListenerContainerFactory} instance to configure
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use
|
||||
*/
|
||||
public void configure(SimpleRabbitListenerContainerFactory factory,
|
||||
ConnectionFactory connectionFactory) {
|
||||
Assert.notNull(factory, "Factory must not be null");
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
RabbitProperties.Listener listenerConfig = this.rabbitProperties.getListener();
|
||||
factory.setAutoStartup(listenerConfig.isAutoStartup());
|
||||
if (listenerConfig.getAcknowledgeMode() != null) {
|
||||
factory.setAcknowledgeMode(listenerConfig.getAcknowledgeMode());
|
||||
}
|
||||
if (listenerConfig.getConcurrency() != null) {
|
||||
factory.setConcurrentConsumers(listenerConfig.getConcurrency());
|
||||
}
|
||||
if (listenerConfig.getMaxConcurrency() != null) {
|
||||
factory.setMaxConcurrentConsumers(listenerConfig.getMaxConcurrency());
|
||||
}
|
||||
if (listenerConfig.getPrefetch() != null) {
|
||||
factory.setPrefetchCount(listenerConfig.getPrefetch());
|
||||
}
|
||||
if (listenerConfig.getTransactionSize() != null) {
|
||||
factory.setTxSize(listenerConfig.getTransactionSize());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-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.
|
||||
|
@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.jms;
|
|||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
|
@ -29,7 +28,6 @@ import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
|
|||
import org.springframework.jms.config.JmsListenerConfigUtils;
|
||||
import org.springframework.jms.support.destination.DestinationResolver;
|
||||
import org.springframework.jms.support.destination.JndiDestinationResolver;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
|
||||
/**
|
||||
* Configuration for Spring 4.1 annotation driven JMS.
|
||||
|
@ -42,41 +40,17 @@ import org.springframework.transaction.jta.JtaTransactionManager;
|
|||
@ConditionalOnClass(EnableJms.class)
|
||||
class JmsAnnotationDrivenConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private DestinationResolver destinationResolver;
|
||||
|
||||
@Autowired(required = false)
|
||||
private JtaTransactionManager transactionManager;
|
||||
|
||||
@Autowired
|
||||
private JmsProperties properties;
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public JmsListenerContainerFactoryConfigurer jmsListenerContainerFactoryConfigurer() {
|
||||
return new JmsListenerContainerFactoryConfigurer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "jmsListenerContainerFactory")
|
||||
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
|
||||
ConnectionFactory connectionFactory) {
|
||||
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
factory.setPubSubDomain(this.properties.isPubSubDomain());
|
||||
if (this.transactionManager != null) {
|
||||
factory.setTransactionManager(this.transactionManager);
|
||||
}
|
||||
else {
|
||||
factory.setSessionTransacted(true);
|
||||
}
|
||||
if (this.destinationResolver != null) {
|
||||
factory.setDestinationResolver(this.destinationResolver);
|
||||
}
|
||||
JmsProperties.Listener listener = this.properties.getListener();
|
||||
factory.setAutoStartup(listener.isAutoStartup());
|
||||
if (listener.getAcknowledgeMode() != null) {
|
||||
factory.setSessionAcknowledgeMode(listener.getAcknowledgeMode().getMode());
|
||||
}
|
||||
String concurrency = listener.formatConcurrency();
|
||||
if (concurrency != null) {
|
||||
factory.setConcurrency(concurrency);
|
||||
}
|
||||
return factory;
|
||||
JmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
|
||||
return configurer.createJmsListenerContainerFactory(connectionFactory);
|
||||
}
|
||||
|
||||
@EnableJms
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright 2012-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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jms;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
|
||||
import org.springframework.jms.config.JmsListenerContainerFactory;
|
||||
import org.springframework.jms.support.destination.DestinationResolver;
|
||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configure {@link JmsListenerContainerFactory} with sensible defaults.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 1.3.3
|
||||
*/
|
||||
public final class JmsListenerContainerFactoryConfigurer {
|
||||
|
||||
private DestinationResolver destinationResolver;
|
||||
|
||||
private JtaTransactionManager transactionManager;
|
||||
|
||||
private JmsProperties jmsProperties;
|
||||
|
||||
/**
|
||||
* Set the {@link DestinationResolver} to use or {@code null} if no destination
|
||||
* resolver should be associated with the factory by default.
|
||||
* @param destinationResolver the {@link DestinationResolver}
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setDestinationResolver(DestinationResolver destinationResolver) {
|
||||
this.destinationResolver = destinationResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link JtaTransactionManager} to use or {@code null} if the JTA
|
||||
* support should not be used.
|
||||
* @param transactionManager the {@link JtaTransactionManager}
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public void setTransactionManager(JtaTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link JmsProperties to use}.
|
||||
* @param jmsProperties the {@link JmsProperties}
|
||||
*/
|
||||
@Autowired
|
||||
public void setJmsProperties(JmsProperties jmsProperties) {
|
||||
this.jmsProperties = jmsProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new and pre-configured {@link DefaultJmsListenerContainerFactory} instance
|
||||
* for the specified {@link ConnectionFactory}.
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use.
|
||||
* @return a pre-configured {@link DefaultJmsListenerContainerFactory}
|
||||
*/
|
||||
public DefaultJmsListenerContainerFactory createJmsListenerContainerFactory(
|
||||
ConnectionFactory connectionFactory) {
|
||||
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
|
||||
configure(factory, connectionFactory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the default settings for the specified jms listener container factory. The
|
||||
* factory can be further tuned and default settings can be overridden.
|
||||
* @param factory the {@link DefaultJmsListenerContainerFactory} instance to configure
|
||||
* @param connectionFactory the {@link ConnectionFactory} to use
|
||||
*/
|
||||
public void configure(DefaultJmsListenerContainerFactory factory,
|
||||
ConnectionFactory connectionFactory) {
|
||||
Assert.notNull(factory, "Factory must not be null");
|
||||
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
|
||||
factory.setConnectionFactory(connectionFactory);
|
||||
factory.setPubSubDomain(this.jmsProperties.isPubSubDomain());
|
||||
if (this.transactionManager != null) {
|
||||
factory.setTransactionManager(this.transactionManager);
|
||||
}
|
||||
else {
|
||||
factory.setSessionTransacted(true);
|
||||
}
|
||||
if (this.destinationResolver != null) {
|
||||
factory.setDestinationResolver(this.destinationResolver);
|
||||
}
|
||||
JmsProperties.Listener listener = this.jmsProperties.getListener();
|
||||
factory.setAutoStartup(listener.isAutoStartup());
|
||||
if (listener.getAcknowledgeMode() != null) {
|
||||
factory.setSessionAcknowledgeMode(listener.getAcknowledgeMode().getMode());
|
||||
}
|
||||
String concurrency = listener.formatConcurrency();
|
||||
if (concurrency != null) {
|
||||
factory.setConcurrency(concurrency);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -212,6 +212,21 @@ public class JmsAutoConfigurationTests {
|
|||
.getPropertyValue("transactionManager"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomContainerFactoryWithConfigurer() {
|
||||
this.context = doLoad(new Class<?>[]{TestConfiguration9.class,
|
||||
EnableJmsConfiguration.class}, "spring.jms.listener.autoStartup=false");
|
||||
assertTrue(this.context.containsBean("jmsListenerContainerFactory"));
|
||||
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context.getBean(
|
||||
"customListenerContainerFactory", JmsListenerContainerFactory.class);
|
||||
assertEquals(DefaultJmsListenerContainerFactory.class,
|
||||
jmsListenerContainerFactory.getClass());
|
||||
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory) jmsListenerContainerFactory)
|
||||
.createListenerContainer(mock(JmsListenerEndpoint.class));
|
||||
assertEquals(DefaultMessageListenerContainer.CACHE_CONSUMER, listenerContainer.getCacheLevel());
|
||||
assertFalse(listenerContainer.isAutoStartup());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPubSubDisabledByDefault() {
|
||||
load(TestConfiguration.class);
|
||||
|
@ -447,6 +462,21 @@ public class JmsAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestConfiguration9 {
|
||||
|
||||
@Bean
|
||||
JmsListenerContainerFactory<?> customListenerContainerFactory(
|
||||
JmsListenerContainerFactoryConfigurer configurer,
|
||||
ConnectionFactory connectionFactory) {
|
||||
DefaultJmsListenerContainerFactory factory = configurer
|
||||
.createJmsListenerContainerFactory(connectionFactory);
|
||||
factory.setCacheLevel(DefaultMessageListenerContainer.CACHE_CONSUMER);
|
||||
return factory;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableJms
|
||||
protected static class EnableJmsConfiguration {
|
||||
|
|
|
@ -3489,6 +3489,44 @@ The following component creates a listener endpoint on the `someQueue` destinati
|
|||
TIP: Check {spring-javadoc}/jms/annotation/EnableJms.{dc-ext}[the Javadoc of `@EnableJms`] for
|
||||
more details.
|
||||
|
||||
If you need to create more `JmsListenerContainerFactory` instances or if you want to override
|
||||
the default, Spring Boot provides a `JmsListenerContainerFactoryConfigurer` that you can use
|
||||
to initialize a `DefaultJmsListenerContainerFactory` with the same settings as the one that
|
||||
is auto-configured.
|
||||
|
||||
For instance, the following exposes another factory that uses a specific `MessageConverter`:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration
|
||||
static class JmsConfiguration {
|
||||
|
||||
@Bean
|
||||
public DefaultJmsListenerContainerFactory myFactory(
|
||||
JmsListenerContainerFactoryConfigurer configurer) {
|
||||
DefaultJmsListenerContainerFactory factory = configurer
|
||||
.createJmsListenerContainerFactory(connectionFactory());
|
||||
factory.setMessageConverter(myMessageConverter());
|
||||
return factory;
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
That you can use in any `@JmsListener`-annotated method as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Component
|
||||
public class MyBean {
|
||||
|
||||
@JmsListener(destination = "someQueue", **containerFactory="myFactory"**)
|
||||
public void processMessage(String content) {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
[[boot-features-amqp]]
|
||||
|
@ -3585,6 +3623,44 @@ The following component creates a listener endpoint on the `someQueue` queue:
|
|||
TIP: Check {spring-amqp-javadoc}/rabbit/annotation/EnableRabbit.{dc-ext}[the Javadoc of `@EnableRabbit`]
|
||||
for more details.
|
||||
|
||||
If you need to create more `RabbitListenerContainerFactory` instances or if you want to override
|
||||
the default, Spring Boot provides a `RabbitListenerContainerFactoryConfigurer` that you can use
|
||||
to initialize a `SimpleRabbitListenerContainerFactory` with the same settings as the one that
|
||||
is auto-configured.
|
||||
|
||||
For instance, the following exposes another factory that uses a specific `MessageConverter`:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration
|
||||
static class RabbitConfiguration {
|
||||
|
||||
@Bean
|
||||
public SimpleRabbitListenerContainerFactory myFactory(
|
||||
RabbitListenerContainerFactoryConfigurer configurer) {
|
||||
SimpleRabbitListenerContainerFactory factory = configurer
|
||||
.createRabbitListenerContainerFactory(connectionFactory());
|
||||
factory.setMessageConverter(myMessageConverter());
|
||||
return factory;
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
That you can use in any `@RabbitListener`-annotated method as follows:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Component
|
||||
public class MyBean {
|
||||
|
||||
@RabbitListener(queues = "someQueue", **containerFactory="myFactory"**)
|
||||
public void processMessage(String content) {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
[[boot-features-email]]
|
||||
|
|
Loading…
Reference in New Issue