diff --git a/docs/src/reference/docbook/router.xml b/docs/src/reference/docbook/router.xml
index 68768f138a..5a467735b8 100644
--- a/docs/src/reference/docbook/router.xml
+++ b/docs/src/reference/docbook/router.xml
@@ -17,7 +17,7 @@
A PayloadTypeRouter will send Messages to the channel as defined by payload-type
mappings.
-
+
- Configuration of PayloadTypeRouter is also supported via the namespace provided by Spring Integration (see ),
- which essentially simplifies configuration by combining <router/> configuration and its corresponding implementation defined using <bean/> element
+ Configuration of the PayloadTypeRouter is also supported via the namespace provided by Spring Integration (see ),
+ which essentially simplifies configuration by combining the <router/> configuration and its corresponding implementation
+ defined using a <bean/> element
into a single and more concise configuration element.
- The example below demonstrates a PayloadTypeRouter configuration which is equivalent to the one above using Spring Integration's namespace support:
+ The example below demonstrates a PayloadTypeRouter configuration which is equivalent to the one above using the namespace support:
@@ -42,7 +43,7 @@
HeaderValueRouter
A HeaderValueRouter will send Messages to the channel based on the individual header value mappings.
- When HeaderValueRouter is created it is initialized with the name of the header to be evaluated.
+ When a HeaderValueRouter is created it is initialized with the name of the header to be evaluated.
The value of the header could be one of two things:
1. Arbitrary value
@@ -51,11 +52,11 @@
2. Channel name
- If arbitrary then additional mapping of these header values to channel names is required, otherwise no additional configuration is needed.
+ If arbitrary then additional mappings for these header values to channel names is required, otherwise no additional configuration is needed.
- Spring Integration provides a simple namespace-based XML configuration to configure HeaderValueRouter.
- The example below demonstrates two types of namespace-based configuration of HeaderValueRouter.
+ Spring Integration provides a simple namespace-based XML configuration to configure a HeaderValueRouter.
+ The example below demonstrates two types of namespace-based configuration for the HeaderValueRouter.
1. Configuration where mapping of header values to channels is required
@@ -69,7 +70,8 @@
exception. If you want to suppress such exceptions and send unresolved messages to the default output channel
(identified with the default-output-channel attribute) set ignore-channel-name-resolution-failures to true.
Normally, messages for which the header value is not explicitly mapped to a channel will be sent to the default-output-channel.
- However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting ignore-channel-name-resolution-failures
+ However, in cases where the header value is mapped to a channel name but the channel cannot be resolved, setting
+ the ignore-channel-name-resolution-failures
attribute to true will result in routing such messages to the default-output-channel.
@@ -106,7 +108,7 @@
- Spring Integration also provides namespace support for RecipientListRouter configuration (see )
+ Spring Integration also provides namespace support for the RecipientListRouter configuration (see )
as the example below demonstrates.
@@ -120,12 +122,14 @@
The 'apply-sequence' flag here has the same effect as it does for a publish-subscribe-channel,
- and like publish-subscribe-channel, it is disabled by default on the recipient-list-router. Refer to
+ and like a publish-subscribe-channel, it is disabled by default on the recipient-list-router. Refer to
for more information.
- Another convenient option to configure RecipientListRouter is to use Spring Expression Language (SpEL) support
+ Another convenient option when configuring a RecipientListRouter is to use Spring Expression Language (SpEL) support
+ as selectors for individual recipient channels. This is similar to using a Filter at the beginning of 'chain' to act as a "Selective Consumer".
+ However, in this case, it's all combined rather concisely into the router's configuration.
@@ -142,7 +146,7 @@
Configuring Router
- Configuring Router with XML
+ Configuring a Content Based Router with XML
The "router" element provides a simple way to connect a router to an input channel and also accepts the
optional default-output-channel attribute. The ref attribute references the bean name of a custom Router implementation
@@ -173,17 +177,17 @@
- Routers and Spring Expression Language (SpEL)
+ Routers and the Spring Expression Language (SpEL)
Sometimes the routing logic may be simple and writing a separate class for it and configuring it as a bean may seem
- like overkill. Since Spring Integration 2.0 we offer an alternative where you can now use
+ like overkill. As of Spring Integration 2.0 we offer an alternative where you can now use
SpEL
to implement simple computations that previously required a custom POJO router.
]]>
In the above configuration the result channel will be computed by the SpEL expression which simply concatenates the value
- of the payload with the literal 'Channel'
+ of the payload with the literal String 'Channel'.
@@ -203,7 +207,7 @@
- Configuring Router with Annotations
+ Configuring a Router with Annotations
When using @Router to annotate a method, the method may return either a
MessageChannel or String type. In the latter case,
@@ -363,7 +367,7 @@ public List<String> route(@Header("orderStatus") OrderStatus status)HeaderValueRouter we clearly see that
there is no mapping sub element:
]]>
- But the configuration is still perfectly valid. So the natural question is what about the maping in the Step 2?
+ But the configuration is still perfectly valid. So the natural question is what about the mapping in the Step 2?
What this means is that Step 2 is now an optional step. If mapping is not defined then the channel identifier
@@ -376,53 +380,54 @@ public List<String> route(@Header("orderStatus") OrderStatus status)
For Example:
- In the above configuration lets assume that the testHeader value is 'kermit' which is now a channel identifier
+ In the above configuration let's assume that the testHeader value is 'kermit' which is now a channel identifier
(Step 1). Since there is no mapping in this router, resolving this channel identifier to a channel name
(Step 2) is impossible and this channel identifier is now treated as channel name. However what if
- there was a mapping but for a different value, the end result would still be the same and that is:
- if new value can not be determined through the process of resolving 'channel identifier' to a 'channel name',
- such 'channel identifier' becomes 'channel name'
+ there was a mapping but for a different value? The end result would still be the same and that is:
+ if new value cannot be determined through the process of resolving the 'channel identifier' to a 'channel name',
+ such 'channel identifier' becomes 'channel name'.
- So all that is left is for Step 3 to resolve channel name ('kermit') to an actual instance of the
- MessageChannel identified by this name. That will be done via a default
- ChannelResolver implementation which is a BeanFactoryChannelResolver which
- basically does a bean lookup by the name provided. So now all messages which contain the header/value pair as testHeader=kermit
- are going to be routed to a 'kermit' MessageChannel.
+ So all that is left is for Step 3 to resolve the channel name ('kermit') to an actual instance of the
+ MessageChannel identified by this name. That will be done via the default
+ ChannelResolver implementation which is a BeanFactoryChannelResolver. It
+ basically does a bean lookup for the name provided. So now all messages which contain the header/value pair as testHeader=kermit
+ are going to be routed to a MessageChannel whose bean name (id) is 'kermit'.
- But what if you want to route these messages to 'simpson' channel? Obviously changing a static configuration will work,
+ But what if you want to route these messages to the 'simpson' channel? Obviously changing a static configuration will work,
but will also require bringing your system down. However if you had access to the channel identifier map, then you
- could just introduce a new mapping where header/value pair is now kermit=simpson, thus allowing Step 2 to treat
- 'kermit' as channel identifier while resolving it to 'simpson' as channel name .
+ could just introduce a new mapping where the header/value pair is now kermit=simpson, thus allowing Step 2 to treat
+ 'kermit' as a channel identifier while resolving it to 'simpson' as the channel name .
The same obviously applies for PayloadTypeRouter where you can now remap or remove a particular payload type
- mapping, and every other router including expression-based routers since their computed value
- will now have a chance to go through Step 2 to be aditionally resolved to the actual channel name.
+ mapping. In fact, it applies to every other router including expression-based routers since their computed values
+ will now have a chance to go through Step 2 to be additionally resolved to the actual channel name.
- In Spring Integration 2.0 the routers hierarchy underwent major refactoring and now any router that is a subclass of the
+ In Spring Integration 2.0 the routers hierarchy underwent significant refactoring so that now any router that is a subclass of the
AbstractMessageRouter (which includes all framework defined routers) is a Dynamic Router simply because the
- channelIdentiferMap is defined at the AbstractMessageRouter with convenient accessors
- and modifiers exposed as public methods allowing you to change/add/remove router mapping at runtime via JMX (see ) or
- the ControlBus (see ) functionality.
+ channelIdentiferMap is defined at the AbstractMessageRouter level. That map's setter method is
+ exposed as a public method along with 'setChannelMapping' and 'removeChannelMapping' methods. These allow you to change/add/remove
+ router mappings at runtime as long as you have a reference to the router itself. It also means that you could expose these same
+ configuration options via JMX (see ) or the Spring Integration ControlBus (see ) functionality.
Control Bus
- One of the way to manage the router mappings is through the Control Bus
+ One way to manage the router mappings is through the Control Bus
pattern which exposes a Control Channel where you can send
control messages to manage and monitor Spring Integration components, including routers.
For more information about the Control Bus see . Typically you would send a control message asking to invoke a
- particular JMX operation on a particular managed component (e.g., router). The two managed operations (methods) that are
- specific to changing router resolution process are:
+ particular operation on a particular managed component (e.g., router). The two managed operations (methods) that are
+ specific to changing the router resolution process are:
public void setChannelMapping(String channelIdentifier, String channelName) -
- will allow you to add new or modify existing mapping of channel identifier to channel name
+ will allow you to add a new or modify an existing mapping between channel identifier and channel name
public void removeChannelMapping(String channelIdentifier) -
@@ -430,12 +435,11 @@ public List<String> route(@Header("orderStatus") OrderStatus status)channel identifier and channel name
- For additional managed operations please refer to an AbstractMessageRouter for more detail
- You can also use your favorite JMX client (e.g., JConsole) and use those operations (methods) to change
- router configuration. For more information on Spring Integration management and monitoring please visit
- .
+ You can also expose a router instance with Spring's JMS support and then use your favorite JMX client (e.g., JConsole) to
+ manage those operations (methods) for changing the router's configuration. For more information on Spring Integration
+ management and monitoring please visit .
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java
index 1a2c42e7d4..731ac17cbb 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/router/AbstractMessageRouter.java
@@ -36,6 +36,8 @@ import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.channel.BeanFactoryChannelResolver;
import org.springframework.integration.support.channel.ChannelResolutionException;
import org.springframework.integration.support.channel.ChannelResolver;
+import org.springframework.jmx.export.annotation.ManagedOperation;
+import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -46,6 +48,7 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
+@ManagedResource
public abstract class AbstractMessageRouter extends AbstractMessageHandler {
private volatile MessageChannel defaultOutputChannel;
@@ -102,7 +105,8 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
this.channelIdentifierMap.putAll(channelIdentifierMap);
}
- public void setChannelMapping(String channelIdentifier, String channelName){
+ @ManagedOperation
+ public void setChannelMapping(String channelIdentifier, String channelName) {
this.channelIdentifierMap.put(channelIdentifier, channelName);
}
@@ -110,7 +114,8 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
* Removes channel mapping for a give channel identifier
* @param channelIdentifier
*/
- public void removeChannelMapping(String channelIdentifier){
+ @ManagedOperation
+ public void removeChannelMapping(String channelIdentifier) {
this.channelIdentifierMap.remove(channelIdentifier);
}