Message Handler Chain
MessageHandlerChain
是 MessageHandler
的一种实现,可以配置为一个单消息端点,同时实际上委托给其他处理程序的链接(例如过滤器、变压器、拆分器等)。当需要以固定的线性级数连接多个处理程序时,这会大大简化配置。例如,在其他组件之前提供一个变压器是相当常见的。同样,当您在链接中的某个其他组件之前提供一个过滤器时,您实际上创建了一个 selective consumer。在任何一种情况下,该链接只需要一个 input-channel
和一个 output-channel
,从而无需为每个组件定义通道。
The MessageHandlerChain
is an implementation of MessageHandler
that can be configured as a single message endpoint while actually delegating to a chain of other handlers, such as filters, transformers, splitters, and so on.
When several handlers need to be connected in a fixed, linear progression, this can lead to a much simpler configuration.
For example, it is fairly common to provide a transformer before other components.
Similarly, when you provide a filter before some other component in a chain, you essentially create a selective consumer.
In either case, the chain requires only a single input-channel
and a single output-channel
, eliminating the need to define channels for each individual component.
|
The |
Spring Integration 的 |
Spring Integration’s |
处理程序链简化了配置,同时在内部保持组件之间相同程度的松散耦合,并且如果在某个时刻需要非线性排列,则修改配置非常简单。
The handler chain simplifies configuration while internally maintaining the same degree of loose coupling between components, and it is trivial to modify the configuration if at some point a non-linear arrangement is required.
在内部,该链被扩展为一个由匿名通道分隔的列出端点的线性设置。回复通道头在链中未被考虑。只有在调用最后一个处理程序之后,结果消息才会转发到回复通道或链的输出通道。由于这个设置,除了最后一个之外的所有处理程序都必须实现 MessageProducer
接口(它提供了 'setOutputChannel()' 方法)。如果设置了 MessageHandlerChain
上的 outputChannel
,则最后一个处理程序只需要一个输出通道。
Internally, the chain is expanded into a linear setup of the listed endpoints, separated by anonymous channels.
The reply channel header is not taken into account within the chain.
Only after the last handler is invoked is the resulting message forwarded to the reply channel or the chain’s output channel.
Because of this setup, all handlers except the last must implement the MessageProducer
interface (which provides a 'setOutputChannel()' method).
If the outputChannel
on the MessageHandlerChain
is set, the last handler needs only an output channel.
与其他端点一样, |
As with other endpoints, the |
在大多数情况下,你不必要自己实现 MessageHandler
。下一节重点关注链元素的命名空间支持。大多数 Spring Integration 端点,例如服务激活器和转换器,都适合在 MessageHandlerChain
中使用。
In most cases, you need not implement MessageHandler
yourself.
The next section focuses on namespace support for the chain element.
Most Spring Integration endpoints, such as service activators and transformers, are suitable for use within a MessageHandlerChain
.
Configuring a Chain
<chain>
元素提供一个 input-channel
属性。如果链中的最后一个元素能够产生回复消息(可选),它还支持一个 output-channel
属性。然后,子元素是过滤器、转换器、分隔器和服务激活器。最后一个元素也可能是路由器或出站通道适配器。以下示例展示了一个链定义:
The <chain>
element provides an input-channel
attribute.
If the last element in the chain is capable of producing reply messages (optional), it also supports an output-channel
attribute.
The sub-elements are then filters, transformers, splitters, and service-activators.
The last element may also be a router or an outbound channel adapter.
The following example shows a chain definition:
<int:chain input-channel="input" output-channel="output">
<int:filter ref="someSelector" throw-exception-on-rejection="true"/>
<int:header-enricher>
<int:header name="thing1" value="thing2"/>
</int:header-enricher>
<int:service-activator ref="someService" method="someMethod"/>
</int:chain>
前面示例中使用的 <header-enricher>
元素在消息上设置了一个名为 thing1
的消息头,其值为 thing2
。头丰富程序是 Transformer
的一个特化,它只处理头值。你可以通过实现一个执行 header 修改和将其作为 bean 连接在一起的 MessageHandler
来获得相同的结果,但 header enrichner 是一个更简单的选择。
The <header-enricher>
element used in the preceding example sets a message header named thing1
with a value of thing2
on the message.
A header enricher is a specialization of Transformer
that touches only header values.
You could obtain the same result by implementing a MessageHandler
that did the header modifications and wiring that as a bean, but the header-enricher is a simpler option.
<chain>
可以配置为消息流的最后一个“封闭框”使用者。对于此解决方案,你可以将其放在 <chain> 的末尾,一些 <outbound-channel-adapter>,如下例所示:
The <chain>
can be configured as the last “closed-box” consumer of the message flow.
For this solution, you can to put it at the end of the <chain> some <outbound-channel-adapter>, as the following example shows:
<int:chain input-channel="input">
<int-xml:marshalling-transformer marshaller="marshaller" result-type="StringResult" />
<int:service-activator ref="someService" method="someMethod"/>
<int:header-enricher>
<int:header name="thing1" value="thing2"/>
</int:header-enricher>
<int:logging-channel-adapter level="INFO" log-full-message="true"/>
</int:chain>
某些属性,例如 order
和 input-channel
不允许在链中使用的组件上指定。轮询子元素也是如此。
Certain attributes, such as order
and input-channel
are not allowed to be specified on components used within a chain.
The same is true for the poller sub-element.
对于 Spring Integration 核心组件,XML 模式本身强制执行一些这些约束。但是,对于非核心组件或你自己的自定义组件,这些约束由 XML 命名空间解析器强制执行,而不是由 XML 模式强制执行。
For the Spring Integration core components, the XML schema itself enforces some of these constraints. However, for non-core components or your own custom components, these constraints are enforced by the XML namespace parser, not by the XML schema.
这些 XML 命名空间解析器约束是在 Spring Integration 2.2 中添加的。如果你尝试使用不允许的属性和元素,XML 命名空间解析器将抛出 BeanDefinitionParsingException
。
These XML namespace parser constraints were added with Spring Integration 2.2.
If you try to use disallowed attributes and elements, the XML namespace parser throws a BeanDefinitionParsingException
.
Using the 'id' Attribute
从 Spring Integration 3.0 开始,如果给链元素一个 id
属性,则该元素的 bean 名称是链的 id
和元素本身的 id
的组合。没有 id
属性的元素不会注册为 bean,但每个元素都会得到一个 componentName
,其中包含链 id
。考虑以下示例:
Beginning with Spring Integration 3.0, if a chain element is given an id
attribute, the bean name for the element is a combination of the chain’s id
and the id
of the element itself.
Elements without id
attributes are not registered as beans, but each one is given a componentName
that includes the chain id
.
Consider the following example:
<int:chain id="somethingChain" input-channel="input">
<int:service-activator id="somethingService" ref="someService" method="someMethod"/>
<int:object-to-json-transformer/>
</int:chain>
在前一个示例中:
In the preceding example:
-
The
<chain>
root element has anid
of 'somethingChain'. Consequently, theAbstractEndpoint
implementation (PollingConsumer
orEventDrivenConsumer
, depending on theinput-channel
type) bean takes this value as its bean name. -
The
MessageHandlerChain
bean acquires a bean alias ('somethingChain.handler'), which allows direct access to this bean from theBeanFactory
. -
The
<service-activator>
is not a fully fledged messaging endpoint (it is not aPollingConsumer
orEventDrivenConsumer
). It is aMessageHandler
within the<chain>
. In this case, the bean name registered with theBeanFactory
is 'somethingChain$child.somethingService.handler'. -
The
componentName
of thisServiceActivatingHandler
takes the same value but without the '.handler' suffix. It becomes 'somethingChain$child.somethingService'. -
The last
<chain>
sub-component,<object-to-json-transformer>
, does not have anid
attribute. ItscomponentName
is based on its position in the<chain>
. In this case, it is 'somethingChain$child#1'. (The final element of the name is the order within the chain, beginning with '#0'). Note, this transformer is not registered as a bean within the application context, so it does not get abeanName
. However, itscomponentName
has a value that is useful for logging and other purposes.
id
属性对 <chain>
元素允许其有资格获得 JMX export,并且可以在 message history 中进行跟踪。您可以使用之前讨论过的相应 bean 名称从 BeanFactory
访问它们。
The id
attribute for <chain>
elements lets them be eligible for JMX export, and they are trackable in the message history.
You can access them from the BeanFactory
by using the appropriate bean name, as discussed earlier.
为 |
It is useful to provide an explicit |
Calling a Chain from within a Chain
有时,你需要从链内嵌套调用另一个链,然后返回并在原始链内继续执行。为了实现这一点,你可以使用消息网关,方法是包含一个 <gateway> 元素,如下例所示:
Sometimes, you need to make a nested call to another chain from within a chain and then come back and continue execution within the original chain. To accomplish this, you can use a messaging gateway by including a <gateway> element, as the following example shows:
<int:chain id="main-chain" input-channel="in" output-channel="out">
<int:header-enricher>
<int:header name="name" value="Many" />
</int:header-enricher>
<int:service-activator>
<bean class="org.foo.SampleService" />
</int:service-activator>
<int:gateway request-channel="inputA"/>
</int:chain>
<int:chain id="nested-chain-a" input-channel="inputA">
<int:header-enricher>
<int:header name="name" value="Moe" />
</int:header-enricher>
<int:gateway request-channel="inputB"/>
<int:service-activator>
<bean class="org.foo.SampleService" />
</int:service-activator>
</int:chain>
<int:chain id="nested-chain-b" input-channel="inputB">
<int:header-enricher>
<int:header name="name" value="Jack" />
</int:header-enricher>
<int:service-activator>
<bean class="org.foo.SampleService" />
</int:service-activator>
</int:chain>
在前一个示例中,通过那里配置的“网关”元素,在 main-chain
处理的末尾调用了 nested-chain-a
。在 nested-chain-a
中,在执行 header 丰富之后调用了 nested-chain-b
。然后流程返回到 nested-chain-b
中完成执行。最后,流程返回到 main-chain
。当在链中定义 <gateway>
元素的嵌套版本时,它不需要 service-interface
属性。相反,它以其当前状态获取消息,并将其放置在 request-channel
属性中定义的通道上。当由该网关发起的下游流程完成时,Message
会返回到网关,并在当前链内继续其旅程。
In the preceding example, nested-chain-a
is called at the end of main-chain
processing by the 'gateway' element configured there.
While in nested-chain-a
, a call to a nested-chain-b
is made after header enrichment.
Then the flow comes back to finish execution in nested-chain-b
.
Finally, the flow returns to main-chain
.
When the nested version of a <gateway>
element is defined in the chain, it does not require the service-interface
attribute.
Instead, it takes the message in its current state and places it on the channel defined in the request-channel
attribute.
When the downstream flow initiated by that gateway completes, a Message
is returned to the gateway and continues its journey within the current chain.