diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java
index 6419de0061..6991836820 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PointToPointChannelParser.java
@@ -16,8 +16,6 @@
package org.springframework.integration.config.xml;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;
import org.springframework.beans.factory.config.TypedStringValue;
@@ -43,8 +41,6 @@ import org.springframework.util.xml.DomUtils;
*/
public class PointToPointChannelParser extends AbstractChannelParser {
- private final Log logger = LogFactory.getLog(this.getClass());
-
@Override
protected BeanDefinitionBuilder buildBeanDefinition(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = null;
@@ -108,12 +104,22 @@ public class PointToPointChannelParser extends AbstractChannelParser {
else {
builder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class);
}
- // unless the 'load-balancer' attribute is explicitly set to 'none',
+ // unless the 'load-balancer' attribute is explicitly set to 'none' or 'load-balancer-ref' is explicitly configured,
// configure the default RoundRobinLoadBalancingStrategy
String loadBalancer = dispatcherElement.getAttribute("load-balancer");
- if ("none".equals(loadBalancer)) {
- builder.addConstructorArgValue(null);
+ String loadBalancerRef = dispatcherElement.getAttribute("load-balancer-ref");
+ if (StringUtils.hasText(loadBalancer) && StringUtils.hasText(loadBalancerRef)){
+ parserContext.getReaderContext().error("'load-balancer' and 'load-balancer-ref' are mutually exclusive", element);
}
+ if (StringUtils.hasText(loadBalancerRef)){
+ builder.addConstructorArgReference(loadBalancerRef);
+ }
+ else {
+ if ("none".equals(loadBalancer)) {
+ builder.addConstructorArgValue(null);
+ }
+ }
+
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, dispatcherElement, "failover");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, dispatcherElement, "max-subscribers");
}
diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd
index 5b9da8b779..8cadcc2186 100644
--- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd
+++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd
@@ -286,12 +286,25 @@
(i.e. one without a queue).
+
+
+
+
+
+
+
+
+ A reference to a bean that implements the 'org.springframework.integration.dispatcher.LoadBalancingStrategy'.
+ This attribute is mutually exclusive with 'load-balancer'.
+
+
+
Defines a load-balancing strategy for the channel's dispatcher.
- The default is a round-robin load
- balancer.
+ The default is a round-robin load balancer.
+ This attribute is mutually exclusive with 'load-balancer-ref'.
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml
new file mode 100644
index 0000000000..b3c25540f3
--- /dev/null
+++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/ChannelWithLoadBalancerRef-fail-config.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml
index ec73516383..f1c6b8240e 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests-context.xml
@@ -1,7 +1,8 @@
@@ -30,7 +31,13 @@
-
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java
index 2fc28dbbe7..a28f8b9d8b 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/channel/config/DispatchingChannelParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2013 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,26 +20,37 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.Map;
+import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.ExecutorChannel;
+import org.springframework.integration.core.MessageHandler;
+import org.springframework.integration.dispatcher.LoadBalancingStrategy;
import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy;
+import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.util.ErrorHandlingTaskExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
+ * @author Oleg Zhurakousky
* @since 1.0.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -116,6 +127,24 @@ public class DispatchingChannelParserTests {
new DirectFieldAccessor(executor).getPropertyValue("executor"));
}
+ @Test
+ public void loadBalancerRef() {
+ MessageChannel channel = channels.get("lbRefChannel");
+ LoadBalancingStrategy lbStrategy = TestUtils.getPropertyValue(channel, "dispatcher.loadBalancingStrategy", LoadBalancingStrategy.class);
+ assertTrue(lbStrategy instanceof SampleLoadBalancingStrategy);
+ }
+
+ @Test
+ public void loadBalancerRefFailWithLoadBalancer() {
+
+ try {
+ new ClassPathXmlApplicationContext("ChannelWithLoadBalancerRef-fail-config.xml", this.getClass());
+ }
+ catch (BeanDefinitionParsingException e) {
+ assertThat(e.getMessage(), Matchers.containsString("'load-balancer' and 'load-balancer-ref' are mutually exclusive"));
+ }
+
+ }
private static Object getDispatcherProperty(String propertyName, MessageChannel channel) {
return new DirectFieldAccessor(
@@ -123,4 +152,11 @@ public class DispatchingChannelParserTests {
.getPropertyValue(propertyName);
}
+ public static class SampleLoadBalancingStrategy implements LoadBalancingStrategy {
+
+ @Override
+ public Iterator getHandlerIterator(Message> message, Collection handlers) {
+ return handlers.iterator();
+ }
+ }
}
diff --git a/src/reference/docbook/channel.xml b/src/reference/docbook/channel.xml
index 819463ea26..633b1e1beb 100644
--- a/src/reference/docbook/channel.xml
+++ b/src/reference/docbook/channel.xml
@@ -199,17 +199,27 @@
The DirectChannel internally delegates to a Message Dispatcher to invoke its
- subscribed Message Handlers, and that dispatcher can have a load-balancing strategy. The load-balancer
- determines how invocations will be ordered in the case that there are multiple handlers subscribed to the
- same channel. When using the namespace support described below, the default strategy is
- "round-robin" which essentially load-balances across the handlers in rotation.
-
- The "round-robin" strategy is currently the only implementation available out-of-the-box in Spring
- Integration. Other strategy implementations may be added in future versions.
-
+ subscribed Message Handlers, and that dispatcher can have a load-balancing strategy exposed via
+ load-balancer or load-balancer-ref attributes (mutually exclusive). The load balancing strategy
+ is used by the Message Dispatcher to help determine how Messages are distributed amongst Message Handlers
+ in the case that there are multiple Message Handlers subscribed to the same channel.
+ As a convinience the load-balancer attribute exposes enumeration of values pointing to pre-existing implementations
+ of LoadBalancingStrategy.
+ The "round-robin" (load-balances across the handlers in rotation) and "none" (for the cases where one wants to explicitely disable load balancing)
+ are the only available values.
+ Other strategy implementations may be added in future versions.
+ However, since version 3.0 you can provide your own implementation of the LoadBalancingStrategy and
+ inject it using load-balancer-ref attribute which should point to a bean that implements
+ LoadBalancingStrategy.
+
+
+
+
+]]>
+ Note that load-balancer or load-balancer-ref attributes are mutually exclusive.
- The load-balancer also works in combination with a boolean failover property.
+ The load-balancing also works in combination with a boolean failover property.
If the "failover" value is true (the default), then the dispatcher will fall back to any subsequent
handlers as necessary when preceding handlers throw Exceptions. The order is determined by an optional
order value defined on the handlers themselves or, if no such value exists, the order in which the
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml
index fac46686a3..74796356c8 100644
--- a/src/reference/docbook/whats-new.xml
+++ b/src/reference/docbook/whats-new.xml
@@ -620,6 +620,16 @@
least 1.
+
+ Direct Channel Load Balancing configuration
+
+ Previously, when configuring LoadBalancingStrategy on the channel's 'dispatcher' sub-element
+ the only available option was to use a pre-defined enumeration of values which did not allow one to set a custom implementation
+ of the LoadBalancingStrategy. Starting with v3.0 you can now use 'load-balancer-ref' to provide
+ a reference to a custom implementation of the LoadBalancingStrategy.
+ For more information see .
+
+
JPA Adapters: first-result attribute