Message Mapping Rules and Conventions
Spring Integration 实现了一个灵活的工具,无需提供额外配置,即可将消息映射到方法及其参数,方法是使用一些默认规则和定义某些约定。以下部分的示例阐述了这些规则。
Spring Integration implements a flexible facility to map messages to methods and their arguments without providing extra configuration, by relying on some default rules and defining certain conventions. The examples in the following sections articulate the rules.
Sample Scenarios
以下示例展示了一个未注释的单个参数(对象或基本类型),它不是一个 Map
或带有非空返回类型的 Properties
对象:
The following example shows a single un-annotated parameter (object or primitive) that is not a Map
or a Properties
object with a non-void return type:
public String doSomething(Object o);
输入参数是一个消息负载。如果参数类型与消息负载不兼容,则尝试使用 Spring 3.0 提供的转换服务转换它。返回值作为返回消息的负载合并。
The input parameter is a message payload. If the parameter type is not compatible with a message payload, an attempt is made to convert it by using a conversion service provided by Spring 3.0. The return value is incorporated as a payload of the returned message.
以下示例展示了一个未注释的单个参数(对象或基本类型),它不是一个 Map
或带有 Message
返回类型的 Properties
:
The following example shows a single un-annotated parameter (object or primitive)that is not a Map
or a Properties
with a Message
return type:
public Message doSomething(Object o);
输入参数是一个消息负载。如果参数类型与消息负载不兼容,则尝试使用 Spring 3.0 提供的转换服务转换它。返回值是一个新构造的消息,发送到下一个目的地。
The input parameter is a message payload. If the parameter type is not compatible with a message payload, an attempt is made to convert it by using a conversion service provided by Spring 3.0. The return value is a newly constructed message that is sent to the next destination.
以下示例展示了一个单个参数,它是一个消息(或其子类)带有一个任意对象或基本类型返回类型:
The following example shows a single parameter that is a message (or one of its subclasses) with an arbitrary object or primitive return type:
public int doSomething(Message msg);
输入参数本身是一个 Message
。返回值变成发送到下一个目的地的 Message
的负载。
The input parameter is itself a Message
.
The return value becomes a payload of the Message
that is sent to the next destination.
以下示例展示了一个单个参数,它是一个 Message
(或其子类),并带有 Message
(或其子类)作为返回类型:
The following example shows a single parameter that is a Message
(or one of its subclasses) with a Message
(or one of its subclasses) as the return type:
public Message doSomething(Message msg);
输入参数本身是一个 Message
。返回值是一个新构造的 Message
,发送到下一个目的地。
The input parameter is itself a Message
.
The return value is a newly constructed Message
that is sent to the next destination.
以下示例展示了一个 Map
或 Properties
类型的单个参数,并带有 Message
作为返回类型:
The following example shows a single parameter of type Map
or Properties
with a Message
as the return type:
public Message doSomething(Map m);
这个有点意思。虽然一开始看起来它必定是直接映射到消息头,但始终优先考虑 Message
负载。这意味着,如果 Message
负载的类型是 Map
,则此输入参数表示一个 Message
负载。但是,如果 Message
负载不是 Map
类型,则转换服务不会尝试转换负载,并且输入参数将映射到消息头。
This one is a bit interesting.
Although, at first, it might seem like an easy mapping straight to message headers, preference is always given to a Message
payload.
This means that if a Message
payload is of type Map
, this input argument represents a Message
payload.
However, if the Message
payload is not of type Map
, the conversion service does not try to convert the payload, and the input argument is mapped to message headers.
以下示例展示了两个参数,其中一个参数是任意类型(对象或基本类型),而不是 Map
或 Properties
对象,另一个参数是 Map
或 Properties
类型的(无论返回):
The following example shows two parameters, where one of them is an arbitrary type (an object or a primitive) that is not a Map
or a Properties
object and the other is of type Map
or Properties
type (regardless of the return):
public Message doSomething(Map h, <T> t);
此组合包含两个输入参数,其中一个类型为 Map
。非 Map
参数(无论顺序如何)映射到 Message
负载,Map
或 Properties
(无论顺序如何)映射到消息头,为您提供了一种与 Message
结构交互得很棒的 POJO 方式。
This combination contains two input parameters where one of them is of type Map
.
The non-Map
parameters (regardless of the order) are mapped to a Message
payload and the Map
or Properties
(regardless of the order) is mapped to message headers, giving you a nice POJO way of interacting with Message
structure.
以下示例展示了没有参数(无论返回):
The following example shows no parameters (regardless of the return):
public String doSomething();
此消息处理程序方法根据发送到此处理程序连接的输入通道的消息进行调用。但是,没有映射的 Message
数据,因此使得 Message
充当事件或触发器来调用处理程序。输出根据 described earlier 规则进行映射。
This message handler method is invoked based on the Message sent to the input channel to which this handler is connected.
However, no Message
data is mapped, thus making the Message
act as event or trigger to invoke the handler.
The output is mapped according to the rules described earlier.
以下示例展示了没有参数和空返回:
The following example shows no parameters and a void return:
public void soSomething();
此示例与上一个示例相同,但不会产生任何输出。
This example is the same as the previous example, but it produces no output.
Annotation-based Mapping
基于注释的映射是将消息映射到方法最安全、最不模棱两可的方法。以下示例说明如何明确地将方法映射到标头:
Annotation-based mapping is the safest and least ambiguous approach to map messages to methods. The following example shows how to explicitly map a method to a header:
public String doSomething(@Payload String s, @Header("someheader") String b)
如您稍后看到的,没有注释这个签名会导致一个模棱两可的条件。然而,通过明确地将第一个参数映射到 Message
有效负载并将第二个参数映射到 someheader
消息头的值,我们可以避免任何歧义。
As you can see later on, without an annotation this signature would result in an ambiguous condition.
However, by explicitly mapping the first argument to a Message
payload and the second argument to a value of the someheader
message header, we avoid any ambiguity.
以下示例与前面的示例几乎相同:
The following example is nearly identical to the preceding example:
public String doSomething(@Payload String s, @RequestParam("something") String b)
@RequestMapping
或任何其他非 Spring Integration 映射注释都无关,因此被忽略,从而使第二个参数未映射。虽然第二个参数可以轻松地映射到有效负载,但只能有一个有效负载。因此,注释使此方法避免歧义。
@RequestMapping
or any other non-Spring Integration mapping annotation is irrelevant and is therefore ignored, leaving the second parameter unmapped.
Although the second parameter could easily be mapped to a payload, there can only be one payload.
Therefore, the annotations keep this method from being ambiguous.
以下示例显示了另一个类似的方法,如果没有注释来阐明意图,它将是模棱两可的:
The following example shows another similar method that would be ambiguous were it not for annotations to clarify the intent:
public String foo(String s, @Header("foo") String b)
唯一的区别是第一个参数被隐式映射到消息有效负载。
The only difference is that the first argument is implicitly mapped to the message payload.
以下示例展示了另一个签名,如果没有注释,肯定会将其视为模棱两可的,因为它有多个参数:
The following example shows yet another signature that would definitely be treated as ambiguous without annotations, because it has more than two arguments:
public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)
此示例尤其成问题,因为它的两个参数是 Map
实例。但是,使用基于注释的映射,可以轻松避免歧义。在此示例中,第一个参数被映射到所有消息头,而第二个和第三个参数被映射到名为 something
和 someotherthing
的消息头的值。有效负载未映射到任何参数。
This example would be especially problematic, because two of its arguments are Map
instances.
However, with annotation-based mapping, the ambiguity is easily avoided.
In this example the first argument is mapped to all the message headers, while the second and third argument map to the values of the message headers named 'something' and 'someotherthing'.
The payload is not being mapped to any argument.
Complex Scenarios
以下示例使用多个参数:
The following example uses multiple parameters:
多个参数可能会在确定适当的映射方面造成很大的歧义。一般的建议是用 @Payload
、@Header
和 @Headers
为您的方法参数添加注释。本节中的示例显示了导致引发异常的模棱两可的情况。
Multiple parameters can create a lot of ambiguity in regards to determining the appropriate mappings.
The general advice is to annotate your method parameters with @Payload
, @Header
, and @Headers
.
The examples in this section show ambiguous conditions that result in an exception being raised.
public String doSomething(String s, int i)
这两个参数的权重相等。因此,无法确定哪个是有效负载。
The two parameters are equal in weight. Therefore, there is no way to determine which one is a payload.
以下示例显示了类似的问题,只有三个参数:
The following example shows a similar problem, only with three parameters:
public String foo(String s, Map m, String b)
虽然 Map 可以轻松映射到消息头,但无法确定如何处理这两个 String 参数。
Although the Map could be easily mapped to message headers, there is no way to determine what to do with the two String parameters.
以下示例显示了另一种模棱两可的方法:
The following example shows another ambiguous method:
public String foo(Map m, Map f)
虽然有人可能会认为可以将一个 Map
映射到消息有效负载,而将另一个映射到消息头,但我们无法依赖顺序。
Although one might argue that one Map
could be mapped to the message payload and the other one to the message headers, we cannot rely on the order.
具有多个不是 ( |
Any method signature with more than one method argument that is not ( |
下一组示例分别展示了导致歧义的多个方法。
The next set of examples each show multiple methods that result in ambiguity.
具有多个方法的消息处理程序基于前面(示例中)描述的相同规则进行映射。但是,某些场景可能仍然看起来令人困惑。
Message handlers with multiple methods are mapped based on the same rules that are described earlier (in the examples). However, some scenarios might still look confusing.
以下示例展示了具有合法(可映射且明确)签名的多个方法:
The following example shows multiple methods with legal (mappable and unambiguous) signatures:
public class Something {
public String doSomething(String str, Map m);
public String doSomething(Map m);
}
(方法具有相同名称或不同名称没有区别)。Message
可以映射到任一方法。当消息有效负载可以映射到 str
并且消息头可以映射到 m
时,将调用第一个方法。第二个方法还可以通过仅将消息头映射到 m
来成为候选。更糟的是,这两个方法具有相同的名字。起初,这看起来可能很模糊,因为具有以下配置:
(Whether the methods have the same name or different names makes no difference).
The Message
could be mapped to either method.
The first method would be invoked when the message payload could be mapped to str
and the message headers could be mapped to m
.
The second method could also be a candidate by mapping only the message headers to m
.
To make matters worse, both methods have the same name.
At first, that might look ambiguous because of the following configuration:
<int:service-activator input-channel="input" output-channel="output" method="doSomething">
<bean class="org.things.Something"/>
</int:service-activator>
它可行,因为映射首先基于有效负载,然后是所有其他内容。换句话说,其第一个参数可以映射到有效负载的方法优先于其他所有方法。
It works because mappings are based on the payload first and everything else next. In other words, the method whose first argument can be mapped to a payload takes precedence over all other methods.
现在考虑一个备用示例,它会产生真正的模棱两可条件:
Now consider an alternate example, which produces a truly ambiguous condition:
public class Something {
public String doSomething(String str, Map m);
public String doSomething(String str);
}
两种方法都具有可以映射到消息有效负载的签名。它们也具有相同的名称。此类处理程序方法将触发异常。但是,如果方法名称不同,则可以使用 method
属性影响映射(在下一个示例中显示)。以下示例显示了两个不同方法名称的相同示例:
Both methods have signatures that could be mapped to a message payload.
They also have the same name.
Such handler methods will trigger an exception.
However, if the method names were different, you could influence the mapping with a method
attribute (shown in the next example).
The following example shows the same example with two different method names:
public class Something {
public String doSomething(String str, Map m);
public String doSomethingElse(String str);
}
以下示例显示了如何使用 method
属性指示映射:
The following example shows how to use the method
attribute to dictate the mapping:
<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse">
<bean class="org.bar.Foo"/>
</int:service-activator>
由于配置显式映射了 doSomethingElse
方法,因此我们消除了歧义。
Because the configuration explicitly maps the doSomethingElse
method, we have eliminated the ambiguity.