INT-3677: Support PPH and SpEL for Container Class
JIRA: https://jira.spring.io/browse/INT-3677 Previously, you could not use a property placeholder or SpEL when defining the `container-class` attribute on message-driven endpoints. Register the container with bean name `adapterId.container`. Also add an alias for the container message listener `adapterId.listener`. Add tests for JMS-backed channels - no code changes needed because a factory bean is used.
This commit is contained in:
committed by
Artem Bilan
parent
123b38a008
commit
093ab7924b
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.jms.ChannelPublishingJmsMessageListener;
|
||||
import org.springframework.integration.jms.JmsMessageDrivenEndpoint;
|
||||
import org.springframework.jms.listener.DefaultMessageListenerContainer;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -111,8 +112,8 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String containerBeanName = this.parseMessageListenerContainer(element, parserContext);
|
||||
String listenerBeanName = this.parseMessageListener(element, parserContext);
|
||||
String containerBeanName = this.parseMessageListenerContainer(element, parserContext, builder.getRawBeanDefinition());
|
||||
String listenerBeanName = this.parseMessageListener(element, parserContext, builder.getRawBeanDefinition());
|
||||
builder.addConstructorArgReference(containerBeanName);
|
||||
builder.addConstructorArgReference(listenerBeanName);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, IntegrationNamespaceUtils.AUTO_STARTUP);
|
||||
@@ -121,7 +122,8 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
|
||||
}
|
||||
|
||||
private String parseMessageListenerContainer(Element element, ParserContext parserContext) {
|
||||
private String parseMessageListenerContainer(Element element, ParserContext parserContext,
|
||||
BeanDefinition adapterBeanDefinition) {
|
||||
String containerClass = element.getAttribute("container-class");
|
||||
if (element.hasAttribute("container")) {
|
||||
if (StringUtils.hasText(containerClass)) {
|
||||
@@ -182,12 +184,16 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
"subscriptionName");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "client-id");
|
||||
builder.addPropertyValue("autoStartup", false);
|
||||
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
|
||||
String beanName = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
|
||||
+ ".container";
|
||||
parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition());
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private String parseMessageListener(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
"org.springframework.integration.jms.ChannelPublishingJmsMessageListener");
|
||||
private String parseMessageListener(Element element, ParserContext parserContext,
|
||||
BeanDefinition adapterBeanDefinition) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(ChannelPublishingJmsMessageListener.class);
|
||||
builder.addPropertyValue("expectReply", this.expectReply);
|
||||
if (this.expectReply) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
|
||||
@@ -233,11 +239,22 @@ public class JmsMessageDrivenEndpointParser extends AbstractSingleBeanDefinition
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "error-channel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converter");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "header-mapper");
|
||||
String alias = adapterBeanNameRoot(element, parserContext, adapterBeanDefinition)
|
||||
+ ".listener";
|
||||
BeanDefinition beanDefinition = builder.getBeanDefinition();
|
||||
String beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, parserContext.getRegistry());
|
||||
BeanComponentDefinition component = new BeanComponentDefinition(beanDefinition, beanName);
|
||||
BeanComponentDefinition component = new BeanComponentDefinition(beanDefinition, beanName, new String[] { alias });
|
||||
parserContext.registerBeanComponent(component);
|
||||
return beanName;
|
||||
}
|
||||
|
||||
private String adapterBeanNameRoot(Element element, ParserContext parserContext,
|
||||
BeanDefinition adapterBeanDefinition) {
|
||||
String beanName = element.getAttribute(ID_ATTRIBUTE);
|
||||
if (!StringUtils.hasText(beanName)) {
|
||||
beanName = BeanDefinitionReaderUtils.generateBeanName(adapterBeanDefinition, parserContext.getRegistry());
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
container-type="simple"/>
|
||||
|
||||
<jms:channel id="withContainerClass" queue-name="custom.container.queue"
|
||||
container-class="org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer" />
|
||||
container-class="${container.class}" />
|
||||
|
||||
<jms:channel id="withContainerClassSpEL" queue-name="custom.container.queue"
|
||||
container-class="#{'org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer'}" />
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package org.springframework.integration.jms.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import java.util.List;
|
||||
@@ -117,6 +115,9 @@ public class JmsChannelParserTests {
|
||||
@Autowired
|
||||
private MessageChannel withContainerClass;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel withContainerClassSpEL;
|
||||
|
||||
@Autowired
|
||||
private MessageBuilderFactory messageBuilderFactory;
|
||||
|
||||
@@ -300,6 +301,14 @@ public class JmsChannelParserTests {
|
||||
assertEquals("custom.container.queue", container.getDestinationName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withContainerClassSpEL() {
|
||||
CustomTestMessageListenerContainer container = TestUtils.getPropertyValue(
|
||||
withContainerClassSpEL, "container",
|
||||
CustomTestMessageListenerContainer.class);
|
||||
assertEquals("custom.container.queue", container.getDestinationName());
|
||||
}
|
||||
|
||||
|
||||
static class TestDestinationResolver implements DestinationResolver {
|
||||
|
||||
|
||||
@@ -173,6 +173,29 @@ public class JmsMessageDrivenChannelAdapterParserTests {
|
||||
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
|
||||
adapter.start();
|
||||
FooContainer container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
|
||||
assertSame(container, context.getBean("adapterWithIdleConsumerLimit.container"));
|
||||
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
|
||||
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
|
||||
assertSame(context.getBean("adapterWithIdleConsumerLimit.listener"),
|
||||
TestUtils.getPropertyValue(container, "messageListener"));
|
||||
adapter.stop();
|
||||
|
||||
adapter = context.getBean("adapterWithIdleConsumerLimit2.adapter", JmsMessageDrivenEndpoint.class);
|
||||
channel = context.getBean("adapterWithIdleConsumerLimit2", MessageChannel.class);
|
||||
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
|
||||
adapter.start();
|
||||
container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
|
||||
assertSame(container, context.getBean("adapterWithIdleConsumerLimit2.container"));
|
||||
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
|
||||
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
|
||||
adapter.stop();
|
||||
|
||||
adapter = context.getBean("org.springframework.integration.jms.JmsMessageDrivenEndpoint#0", JmsMessageDrivenEndpoint.class);
|
||||
channel = context.getBean("in", MessageChannel.class);
|
||||
assertSame(channel, TestUtils.getPropertyValue(adapter, "listener.gatewayDelegate.requestChannel"));
|
||||
adapter.start();
|
||||
container = TestUtils.getPropertyValue(adapter, "listenerContainer", FooContainer.class);
|
||||
assertSame(container, context.getBean("org.springframework.integration.jms.JmsMessageDrivenEndpoint#0.container"));
|
||||
assertEquals(33, new DirectFieldAccessor(container).getPropertyValue("idleConsumerLimit"));
|
||||
assertEquals(3, new DirectFieldAccessor(container).getPropertyValue("cacheLevel"));
|
||||
adapter.stop();
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
queue=testQueue
|
||||
concurrency=5-25
|
||||
concurrency=5-25
|
||||
container.class=org.springframework.integration.jms.config.JmsChannelParserTests$CustomTestMessageListenerContainer
|
||||
|
||||
@@ -3,21 +3,47 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:jms="http://www.springframework.org/schema/integration/jms"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jms
|
||||
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
|
||||
<util:properties id="props">
|
||||
<prop key="container.class">org.springframework.integration.jms.config.JmsMessageDrivenChannelAdapterParserTests$FooContainer</prop>
|
||||
</util:properties>
|
||||
|
||||
<context:property-placeholder properties-ref="props"/>
|
||||
|
||||
<jms:message-driven-channel-adapter id="adapterWithIdleConsumerLimit"
|
||||
connection-factory="testConnectionFactory"
|
||||
destination-name="testQueue"
|
||||
container-class="org.springframework.integration.jms.config.JmsMessageDrivenChannelAdapterParserTests$FooContainer"
|
||||
container-class="${container.class}"
|
||||
idle-consumer-limit="33"
|
||||
cache-level="3"
|
||||
auto-startup="false" />
|
||||
|
||||
<jms:message-driven-channel-adapter id="adapterWithIdleConsumerLimit2"
|
||||
connection-factory="testConnectionFactory"
|
||||
destination-name="testQueue"
|
||||
container-class="#{props['container.class']}"
|
||||
idle-consumer-limit="33"
|
||||
cache-level="3"
|
||||
auto-startup="false" />
|
||||
|
||||
<!-- no id -->
|
||||
<jms:message-driven-channel-adapter channel="in"
|
||||
connection-factory="testConnectionFactory"
|
||||
destination-name="testQueue"
|
||||
container-class="#{props['container.class']}"
|
||||
idle-consumer-limit="33"
|
||||
cache-level="3"
|
||||
auto-startup="false" />
|
||||
|
||||
<si:channel id="in" />
|
||||
|
||||
<bean id="testConnectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.integration.jms.StubConnection">
|
||||
|
||||
Reference in New Issue
Block a user