此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
消息映射规则和约定
Spring Integration实现了一种灵活的工具,通过依赖一些默认规则和定义某些约定,将消息映射到方法及其参数,而无需提供额外的配置。 以下部分中的示例阐明了规则。
示例方案
以下示例显示了一个未注释的参数(对象或基元),该参数不是Map
或Properties
具有非 void 返回类型的对象:
public String doSomething(Object o);
输入参数是消息有效负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值被合并为返回消息的有效负载。
以下示例显示了一个未注释的参数(对象或基元),该参数不是Map
或Properties
使用Message
返回类型:
public Message doSomething(Object o);
输入参数是消息有效负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值是发送到下一个目标的新构造消息。
以下示例显示了一个参数,该参数是具有任意对象或原始返回类型的消息(或其子类之一):
public int doSomething(Message msg);
输入参数本身是Message
.
返回值成为Message
发送到下一个目的地。
以下示例显示了一个参数,该参数是Message
(或其子类之一)与Message
(或其子类之一)作为返回类型:
public Message doSomething(Message msg);
输入参数本身是Message
.
返回值是新构造的Message
发送到下一个目的地。
以下示例显示了类型为Map
或Properties
使用Message
作为返回类型:
public Message doSomething(Map m);
这个有点意思。
尽管乍一看,直接映射到消息头似乎很容易,但始终优先考虑Message
有效载荷。
这意味着,如果Message
有效负载的类型为Map
,则此输入参数表示Message
有效载荷。
但是,如果Message
有效负载不是类型Map
,转换服务不会尝试转换有效负载,并且输入参数将映射到消息头。
以下示例显示了两个参数,其中一个是任意类型(对象或基元),不是Map
或Properties
object 的,另一个是Map
或Properties
类型(无论返回结果如何):
public Message doSomething(Map h, <T> t);
此组合包含两个输入参数,其中一个类型为Map
.
非Map
参数(无论顺序如何)都映射到Message
payload 和Map
或Properties
(无论顺序如何)都映射到消息头,为您提供了一种很好的 POJO 交互方式Message
结构。
以下示例不显示任何参数(无论返回结果如何):
public String doSomething();
此消息处理程序方法是根据发送到此处理程序所连接的输入通道的消息调用的。
但是,没有Message
数据被映射,从而使Message
充当事件或触发器来调用处理程序。
输出根据前面描述的规则进行映射。
以下示例显示没有参数和 void 返回:
public void soSomething();
此示例与上一个示例相同,但不产生任何输出。
基于注释的映射
基于注释的映射是将消息映射到方法的最安全且最不模糊的方法。 以下示例演示如何将方法显式映射到标头:
public String doSomething(@Payload String s, @Header("someheader") String b)
正如您稍后看到的,如果没有注释,此签名将导致不明确的情况。
但是,通过将第一个参数显式映射到Message
payload 和第二个参数的值someheader
message header 中,我们避免了任何歧义。
以下示例与前面的示例几乎相同:
public String doSomething(@Payload String s, @RequestParam("something") String b)
@RequestMapping
或任何其他非 Spring Integration 映射注释都是无关紧要的,因此被忽略,使第二个参数未映射。
尽管第二个参数可以很容易地映射到有效负载,但只能有一个有效负载。
因此,注释可以防止此方法不明确。
以下示例显示了另一种类似的方法,如果没有注释来澄清意图,该方法将是模棱两可的:
public String foo(String s, @Header("foo") String b)
唯一的区别是第一个参数隐式映射到消息有效负载。
以下示例显示了另一个签名,如果没有注释,它肯定会被视为不明确,因为它有两个以上的参数:
public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)
这个例子尤其成问题,因为它的两个参数是Map
实例。
但是,使用基于注释的映射,可以轻松避免歧义。
在此示例中,第一个参数映射到所有消息头,而第二个和第三个参数映射到名为“something”和“someotherthing”的消息头的值。
有效负载未映射到任何参数。
复杂场景
以下示例使用多个参数:
多个参数可能会在确定适当的映射时产生很多歧义。
一般建议是用@Payload
,@Header
和@Headers
.
本节中的示例显示了导致引发异常的不明确条件。
public String doSomething(String s, int i)
这两个参数的权重相等。 因此,无法确定哪一个是有效载荷。
以下示例显示了类似的问题,仅使用三个参数:
public String foo(String s, Map m, String b)
尽管 Map 可以轻松映射到消息标头,但无法确定如何处理这两个 String 参数。
以下示例显示了另一种模棱两可的方法:
public String foo(Map m, Map f)
尽管有人可能会争辩说Map
可以映射到消息有效负载,另一个映射到消息头,我们不能依赖顺序。
任何具有多个方法参数的方法签名,该参数不是 (Map ,<T> )并使用未注释的参数会导致不明确的条件并触发异常。 |
下一组示例分别显示了多种导致歧义的方法。
具有多个方法的消息处理程序根据前面描述的相同规则(在示例中)进行映射。 但是,某些场景可能看起来仍然令人困惑。
以下示例显示了具有合法(可映射且明确)签名的多个方法:
public class Something {
public String doSomething(String str, Map m);
public String doSomething(Map m);
}
(这些方法的名称相同还是名称不同没有区别)。
这Message
可以映射到任一方法。
当消息有效负载可以映射到str
并且消息头可以映射到m
.
第二种方法也可以通过仅将消息头映射到m
.
更糟糕的是,这两种方法都有相同的名称。
起初,由于以下配置,这可能看起来不明确:
<int:service-activator input-channel="input" output-channel="output" method="doSomething">
<bean class="org.things.Something"/>
</int:service-activator>
它之所以有效,是因为映射首先基于有效负载,然后是其他所有内容。 换句话说,其第一个参数可以映射到有效负载的方法优先于所有其他方法。
现在考虑一个替代示例,它会产生一个真正模棱两可的条件:
public class Something {
public String doSomething(String str, Map m);
public String doSomething(String str);
}
这两种方法都有可以映射到消息有效负载的签名。
它们也有相同的名称。
此类处理程序方法将触发异常。
但是,如果方法名称不同,则可以使用method
属性(如下一个示例所示)。
以下示例显示了具有两个不同方法名称的同一示例:
public class Something {
public String doSomething(String str, Map m);
public String doSomethingElse(String str);
}
以下示例演示如何使用method
属性来指示映射:
<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse">
<bean class="org.bar.Foo"/>
</int:service-activator>
由于配置显式映射了doSomethingElse
方法,我们消除了歧义。