Customize concurrency at listener level
Prior to this commit, customizing the concurrency to use fo a given JMS listener involved to define it in a specific listener-container. As this is quite restrictive, users may stop using the XML namespace support altogether to fallback on regular abstract bean definition for the container. This commit adds a concurrency attribute to the jms and jca listener element as well as on the @JmsListener annotation. If the value is set, it takes precedence; otherwise the value provided by the factory is used. Issue: SPR-11988
This commit is contained in:
@@ -107,4 +107,13 @@ public @interface JmsListener {
|
||||
*/
|
||||
String selector() default "";
|
||||
|
||||
/**
|
||||
* The concurrency for the listener, if any.
|
||||
* <p>The concurrency limits can be a "lower-upper" String, e.g. "5-10", or a simple
|
||||
* upper limit String, e.g. "10" (the lower limit will be 1 in this case).
|
||||
* <p>The underlying container may or may not support all features. For instance, it
|
||||
* may not be able to scale: in that case only the upper value is used.
|
||||
*/
|
||||
String concurrency() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -181,6 +181,9 @@ public class JmsListenerAnnotationBeanPostProcessor implements BeanPostProcessor
|
||||
if (StringUtils.hasText(jmsListener.subscription())) {
|
||||
endpoint.setSubscription(jmsListener.subscription());
|
||||
}
|
||||
if (StringUtils.hasText(jmsListener.concurrency())) {
|
||||
endpoint.setConcurrency(jmsListener.concurrency());
|
||||
}
|
||||
|
||||
JmsListenerContainerFactory<?> factory = null;
|
||||
String containerFactoryBeanName = jmsListener.containerFactory();
|
||||
|
||||
@@ -42,6 +42,8 @@ public abstract class AbstractJmsListenerEndpoint implements JmsListenerEndpoint
|
||||
|
||||
private String selector;
|
||||
|
||||
private String concurrency;
|
||||
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
@@ -95,6 +97,23 @@ public abstract class AbstractJmsListenerEndpoint implements JmsListenerEndpoint
|
||||
return this.selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a concurrency for the listener, if any.
|
||||
* <p>The concurrency limits can be a "lower-upper" String, e.g. "5-10", or a simple
|
||||
* upper limit String, e.g. "10" (the lower limit will be 1 in this case).
|
||||
* <p>The underlying container may or may not support all features. For instance, it
|
||||
* may not be able to scale: in that case only the upper value is used.
|
||||
*/
|
||||
public void setConcurrency(String concurrency) {
|
||||
this.concurrency = concurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the concurrency for the listener, if any.
|
||||
*/
|
||||
public String getConcurrency() {
|
||||
return concurrency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupMessageContainer(MessageListenerContainer container) {
|
||||
@@ -121,6 +140,9 @@ public abstract class AbstractJmsListenerEndpoint implements JmsListenerEndpoint
|
||||
if (getSelector() != null) {
|
||||
container.setMessageSelector(getSelector());
|
||||
}
|
||||
if (getConcurrency() != null) {
|
||||
container.setConcurrency(getConcurrency());
|
||||
}
|
||||
setupMessageListener(container);
|
||||
}
|
||||
|
||||
@@ -140,6 +162,9 @@ public abstract class AbstractJmsListenerEndpoint implements JmsListenerEndpoint
|
||||
if (getSelector() != null) {
|
||||
activationSpecConfig.setMessageSelector(getSelector());
|
||||
}
|
||||
if (getConcurrency() != null) {
|
||||
activationSpecConfig.setConcurrency(getConcurrency());
|
||||
}
|
||||
setupMessageListener(container);
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,15 @@ abstract class AbstractListenerContainerParser implements BeanDefinitionParser {
|
||||
}
|
||||
configDef.getPropertyValues().add("messageSelector", selector);
|
||||
}
|
||||
|
||||
if (ele.hasAttribute(CONCURRENCY_ATTRIBUTE)) {
|
||||
String concurrency = ele.getAttribute(CONCURRENCY_ATTRIBUTE);
|
||||
if (!StringUtils.hasText(concurrency)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Listener 'concurrency' attribute contains empty value.", ele);
|
||||
}
|
||||
configDef.getPropertyValues().add("concurrency", concurrency);
|
||||
}
|
||||
}
|
||||
|
||||
protected PropertyValues parseCommonContainerProperties(Element ele, ParserContext parserContext) {
|
||||
|
||||
@@ -70,10 +70,10 @@ class JcaListenerContainerParser extends AbstractListenerContainerParser {
|
||||
containerDef.setSource(context.getSource());
|
||||
containerDef.setBeanClassName("org.springframework.jms.listener.endpoint.JmsMessageEndpointManager");
|
||||
|
||||
containerDef.getPropertyValues().addPropertyValues(context.getContainerValues());
|
||||
applyContainerValues(context, containerDef);
|
||||
|
||||
|
||||
BeanDefinition activationSpec = getActivationSpecConfigBeanDefinition(context.getContainerValues());
|
||||
BeanDefinition activationSpec = getActivationSpecConfigBeanDefinition(containerDef.getPropertyValues());
|
||||
parseListenerConfiguration(context.getListenerElement(), context.getParserContext(), activationSpec);
|
||||
|
||||
String phase = context.getContainerElement().getAttribute(PHASE_ATTRIBUTE);
|
||||
@@ -84,6 +84,21 @@ class JcaListenerContainerParser extends AbstractListenerContainerParser {
|
||||
return containerDef;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property values provided by the factory element contains a mutable property (the
|
||||
* activation spec config). To avoid changing the bean definition from the parent, a clone
|
||||
* bean definition is created for the container being configured.
|
||||
*/
|
||||
private void applyContainerValues(ListenerContainerParserContext context, RootBeanDefinition containerDef) {
|
||||
// Apply settings from the container
|
||||
containerDef.getPropertyValues().addPropertyValues(context.getContainerValues());
|
||||
|
||||
// Clone the activationSpecConfig property value as it is mutable
|
||||
PropertyValue pv = containerDef.getPropertyValues().getPropertyValue("activationSpecConfig");
|
||||
RootBeanDefinition activationSpecConfig = new RootBeanDefinition((RootBeanDefinition) pv.getValue());
|
||||
containerDef.getPropertyValues().add("activationSpecConfig", activationSpecConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean indicatesPubSub(PropertyValues propertyValues) {
|
||||
BeanDefinition configDef = getActivationSpecConfigBeanDefinition(propertyValues);
|
||||
|
||||
@@ -92,7 +92,6 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
|
||||
|
||||
// Set all container values
|
||||
containerDef.getPropertyValues().addPropertyValues(context.getContainerValues());
|
||||
parseListenerConfiguration(context.getListenerElement(), context.getParserContext(), containerDef);
|
||||
|
||||
Element containerEle = context.getContainerElement();
|
||||
String containerType = containerEle.getAttribute(CONTAINER_TYPE_ATTRIBUTE);
|
||||
@@ -116,6 +115,9 @@ class JmsListenerContainerParser extends AbstractListenerContainerParser {
|
||||
containerDef.getPropertyValues().add("phase", phase);
|
||||
}
|
||||
|
||||
// Parse listener specific settings
|
||||
parseListenerConfiguration(context.getListenerElement(), context.getParserContext(), containerDef);
|
||||
|
||||
return containerDef;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,11 @@ public abstract class AbstractMessageListenerContainer
|
||||
private boolean acceptMessagesWhileStopping = false;
|
||||
|
||||
|
||||
/**
|
||||
* Specify concurrency limits.
|
||||
*/
|
||||
public abstract void setConcurrency(String concurrency);
|
||||
|
||||
/**
|
||||
* Set the destination to receive messages from.
|
||||
* <p>Alternatively, specify a "destinationName", to be dynamically
|
||||
|
||||
@@ -295,6 +295,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
|
||||
* ({@link #setConcurrentConsumers}) and will slowly scale up to the maximum number
|
||||
* of consumers {@link #setMaxConcurrentConsumers} in case of increasing load.
|
||||
*/
|
||||
@Override
|
||||
public void setConcurrency(String concurrency) {
|
||||
try {
|
||||
int separatorIndex = concurrency.indexOf('-');
|
||||
|
||||
@@ -114,6 +114,7 @@ public class SimpleMessageListenerContainer extends AbstractMessageListenerConta
|
||||
* {@link DefaultMessageListenerContainer}. For this local listener container,
|
||||
* generally use {@link #setConcurrentConsumers} instead.
|
||||
*/
|
||||
@Override
|
||||
public void setConcurrency(String concurrency) {
|
||||
try {
|
||||
int separatorIndex = concurrency.indexOf('-');
|
||||
|
||||
Reference in New Issue
Block a user