diff --git a/src/docbkx/router.xml b/src/docbkx/router.xml index 5bb0fa182e..c089a3960b 100644 --- a/src/docbkx/router.xml +++ b/src/docbkx/router.xml @@ -201,5 +201,206 @@ public List<String> route(@Header("orderStatus") OrderStatus status) For routing of XML-based Messages, including XPath support, see . + +
+ Dynamic Routers + + So as you can see, Spring Integration provides quite a few different router configurations for most common + content-based routing use cases as well as the option of implementing custom routers as POJOs. + For example; Payload Type Router provides a simple way to configure a router which computes channels + based on the payload type of the incoming Message while Header Value Router provides the + same convenience in configuring a router which computes channels based on evaluating the value + of a particular Message Header. There is also an expression-based (SpEL) routers where the channel + is determined based on evaluating an expression which gives these type of routers some dynamic characteristics. + + + However these routers share one common attribute - static configuration. Even in the case of + expression-based routers, the expression itself is defined as part of the router configuration which means that + the same expression operating on the same value will always result in the computation of the same channel. + This is good in most cases since such routes are well defined and therefore predictable. But there are times when we + need to change router configurations dynamically so message flows could be routed to a different channel. + + For example: + + You might want to bring down some part of your system for maintenance. So, temporarily you want to re-reroute + messages to a different message flow. Or you may want to introduce more granularity to your message flow by adding another + route to handle a more concrete type of java.lang.Number (in cases of Payload Type Router). + + + Unfortunately with static router configuration to accomplish this you'd have to bring down your entire application, + change the configuration of the router (change routes) and bring it back up. This is obviously not the solution. + + + + Dynamic Router + + pattern describes the mechanisms by which one can change/configure routers dynamically without + bringing down your system or individual routers.  + + + Before we get into the specifics of how it is accomplished in Spring Integration lets quickly summarize the + typical flow of the router, which consists of 3 simple steps: + + + Step 1 - Compute channel identifier which is a value calculated by the + router once it receives the Message. Typically it is a String or and instance of the actual + MessageChannel. + + + Step 2 - Resolve channel identifier to channel name. We'll describe + specifics of this process in a moment. + + + Step 3 - Resolve channel name to the actual MessageChannel + + + + + + There is not much that could be done with regard to router dynamics if Step 1 results in the actual instance of the + MessageChannel simply because MessageChannel is the final product of any + router's job. However, if Step 1 results in channel identifier that is not and instance of MessageChannel, + then there are quite a few possibilities to influence the process of calculating what will be the final instance of the Message Channel. + Lets look at couple of the examples in the context of the 3 steps mentioned above:  + + + Payload Type Router + + + + + +]]> + + + Within the context of the Payload Type Router the 3 steps mentioned above would be realized as: + + + Step 1 - Compute channel identifier which is the fully qualified name of the payload type + (e.g., java.lang.String). + + + Step 2 - Resolve channel identifier to channel name where + the result of the previous step is used to select the appropriate value from the payload type mapping + defined via mapping element. + + + Step 3 - Resolve channel name to the actual instance of the + MessageChannel where using ChannelResolver router will obtain a + reference to a bean (which is hopefully a MessageChannel) identified by the result of the + previous step. + + + In other words each step feeds the next step until thr process completes. + + + Header Value Router + + + + + +]]> + + + Similar to the PayloadTypeRouter: + + + Step 1 - Compute channel identifier which is the value of the header identified by the + header-name attribute. + + + Step 2 - Resolve channel identifier to channel name where + the result of the previous step is used to select the appropriate value from the general mapping + defined via mapping element. + + + Step 3 - Resolve channel name to the actual instance of the + MessageChannel where using ChannelResolver router will obtain a + reference to a bean (which is hopefully a MessageChannel) identified by the result of the + previous step. + + + + + The above two configurations of two different router types look almost identical. + However if we look at the different configuration of the HeaderValueRouter we clearly see that + there is no mapping sub element: + ]]> + But configuration is still perfectly valid. So the natural question is what about the maping 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 + value computed in Step 1 will automatically be treated as the channel name which will now be resolved to the + actual MessageChannel in the Step 3. What it also means is that Step 2 is one of the key steps to + provide dynamic characteristics to the routers, since it introduces a process which + allows you to change the way 'channel identifier' resolves to 'channel name', + thus influencing the process of determining the final instance of the MessageChannel from the initial + channel identifier.  + + For Example: + + In the above configuration lets 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 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' + + + 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 default + ChannelResolver implementation which is 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. + + + But what if you want to route these messages to 'simpson' channel? Obviously changing static configuration would work, + but would also require bringing your system down. However if you had access to 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 . + + + 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. + + + In Spring Integration 2.0 routers hierarchy underwent major refactoring and now any router that is a subclass of the + AbstractMessageRouter (all framework defined routers) is a Dynamic Router simply because + 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 section section 29) or + ControlBus (see section section 29.7) functionality.  + + + + Control Bus + + + One of the way to manage the router mappings is through the Control Bus + which exposes a Control Channel where you can send + control messages to manage and monitor Spring Integration components which includes routers. + For more information about the Control Bus see section 29.7. 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: + + + public void setChannelMapping(String channelIdentifier, String channelName) - + will allow you to add new or modify existing mapping of channel identifier to channel name + + + public void removeChannelMapping(String channelIdentifier) - + will allow you to remove a particular channel mapping, thus disconnecting the relationship between + channel identifier and channel name + + + There are obviously other managed operations, so 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 + section 29 of this manual. + +
\ No newline at end of file