消息映射规则和约定

Spring 集成通过依赖一些默认规则和定义某些约定,实现了一种灵活的工具,可以将消息映射到方法及其参数,而无需提供额外的配置。 以下各节中的示例阐明了这些规则。spring-doc.cadn.net.cn

示例场景

以下示例显示了一个未注释的参数(对象或基元),该参数不是MapPropertiesObject 的 object:spring-doc.cadn.net.cn

public String doSomething(Object o);

input 参数是消息负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值将合并为返回消息的有效负载。spring-doc.cadn.net.cn

以下示例显示了一个未注释的参数(对象或基元),该参数不是MapProperties替换为Message返回类型:spring-doc.cadn.net.cn

public Message doSomething(Object o);

input 参数是消息负载。 如果参数类型与消息有效负载不兼容,则尝试使用 Spring 3.0 提供的转换服务对其进行转换。 返回值是发送到下一个目标的新构造的消息。spring-doc.cadn.net.cn

下面的示例显示了一个参数,该参数是具有任意对象或原始返回类型的消息(或其子类之一):spring-doc.cadn.net.cn

public int doSomething(Message msg);

输入参数本身是一个Message. 返回值将成为Message,该 ID 将被发送到下一个目的地。spring-doc.cadn.net.cn

以下示例显示了一个参数,该参数是Message(或其子类之一)替换为Message(或其子类之一)作为返回类型:spring-doc.cadn.net.cn

public Message doSomething(Message msg);

输入参数本身是一个Message. 返回值是新构造的Message,该 ID 将被发送到下一个目的地。spring-doc.cadn.net.cn

以下示例显示了MapProperties替换为Message作为返回类型:spring-doc.cadn.net.cn

public Message doSomething(Map m);

这个有点有趣。 尽管乍一看,直接映射到消息标头似乎很容易,但始终优先考虑Message有效载荷。 这意味着,如果Messagepayload 的类型为Map,则此 input 参数表示Message有效载荷。 但是,如果Messagepayload 不是类型Map,则转换服务不会尝试转换有效负载,并且 input 参数将映射到消息标头。spring-doc.cadn.net.cn

以下示例显示了两个参数,其中一个参数是任意类型(对象或基元),而不是MapPropertiesobject 的 object 类型为MapPropertiestype (无论返回值如何):spring-doc.cadn.net.cn

public Message doSomething(Map h, <T> t);

此组合包含两个输入参数,其中一个是Map. 非Map参数(无论顺序如何)映射到Messagepayload 和MapProperties(无论顺序如何)映射到消息标头,为您提供一种很好的 POJO 交互方式Message结构。spring-doc.cadn.net.cn

以下示例显示无参数(无论返回结果如何):spring-doc.cadn.net.cn

public String doSomething();

此消息处理程序方法是根据发送到此处理程序所连接的输入通道的 Message 调用的。 然而,没有Messagedata 被映射,从而使Message充当事件或触发器来调用处理程序。 根据前面描述的规则映射输出。spring-doc.cadn.net.cn

以下示例显示无参数和 void 返回:spring-doc.cadn.net.cn

public void soSomething();

此示例与上一个示例相同,但它不会生成任何输出。spring-doc.cadn.net.cn

基于注释的映射

基于 Comments 的映射是将消息映射到方法的最安全且最不明确的方法。 下面的示例演示如何将方法显式映射到标头:spring-doc.cadn.net.cn

public String doSomething(@Payload String s, @Header("someheader") String b)

正如您稍后所看到的,如果没有 Annotation,此签名将导致模棱两可的条件。 但是,通过将第一个参数显式映射到Messagepayload 和第二个参数设置为someheadermessage 标头,我们避免了任何歧义。spring-doc.cadn.net.cn

以下示例与前面的示例几乎相同:spring-doc.cadn.net.cn

public String doSomething(@Payload String s, @RequestParam("something") String b)

@RequestMapping或任何其他非 Spring 集成映射注释都是无关紧要的,因此被忽略,使第二个参数未映射。 尽管第二个参数可以很容易地映射到有效负载,但只能有一个有效负载。 因此,注释使此方法不明确。spring-doc.cadn.net.cn

以下示例显示了另一种类似的方法,如果不是 annotation 来阐明意图,该方法将是模棱两可的:spring-doc.cadn.net.cn

public String foo(String s, @Header("foo") String b)

唯一的区别是第一个参数隐式映射到消息有效负载。spring-doc.cadn.net.cn

以下示例显示了另一个签名,如果没有注释,该签名肯定会被视为不明确,因为它具有两个以上的参数:spring-doc.cadn.net.cn

public String soSomething(@Headers Map m, @Header("something") Map f, @Header("someotherthing") String bar)

这个例子尤其有问题,因为它的两个参数是Map实例。 但是,使用基于注释的映射,可以轻松避免歧义。 在此示例中,第一个参数映射到所有消息标头,而第二个和第三个参数映射到名为 'something' 和 'someotherthing' 的消息标头的值。 有效负载未映射到任何参数。spring-doc.cadn.net.cn

复杂场景

以下示例使用多个参数:spring-doc.cadn.net.cn

多个参数可能会在确定适当的映射时产生很多歧义。 一般的建议是用@Payload,@Header@Headers. 本节中的示例显示了导致引发异常的不明确条件。spring-doc.cadn.net.cn

public String doSomething(String s, int i)

这两个参数的权重相等。 因此,无法确定哪一个是有效负载。spring-doc.cadn.net.cn

以下示例显示了一个类似的问题,只有三个参数:spring-doc.cadn.net.cn

public String foo(String s, Map m, String b)

尽管 Map 可以很容易地映射到消息头,但无法确定如何处理这两个 String 参数。spring-doc.cadn.net.cn

以下示例显示了另一种不明确的方法:spring-doc.cadn.net.cn

public String foo(Map m, Map f)

尽管有人可能会争辩说Map可以映射到消息 payload,另一个映射到消息头,我们不能依赖 order。spring-doc.cadn.net.cn

具有多个方法参数且不是 (Map,<T>) 和未注释的参数会导致不明确的条件并触发异常。

下一组示例分别显示了导致歧义的多种方法。spring-doc.cadn.net.cn

具有多个方法的消息处理程序根据前面描述的相同规则进行映射(在示例中)。 但是,某些方案可能仍然看起来令人困惑。spring-doc.cadn.net.cn

以下示例显示了具有合法(可映射和明确)签名的多种方法:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomething(Map m);
}

(方法具有相同的名称或不同的名称没有区别)。 这Message可以映射到任一方法。 当消息有效负载可以映射到str并且消息标头可以映射到m. 第二种方法也可以是候选方法,只需将消息标头映射到m. 更糟糕的是,这两种方法具有相同的名称。 起初,由于以下配置,这可能看起来模棱两可:spring-doc.cadn.net.cn

<int:service-activator input-channel="input" output-channel="output" method="doSomething">
    <bean class="org.things.Something"/>
</int:service-activator>

它之所以有效,是因为 Map 首先基于有效负载,然后基于其他所有内容。 换句话说,其第一个参数可以映射到有效负载的方法优先于所有其他方法。spring-doc.cadn.net.cn

现在考虑另一个示例,它会产生一个真正模棱两可的条件:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomething(String str);
}

这两种方法都具有可以映射到消息有效负载的签名。 它们也具有相同的名称。 此类处理程序方法将触发异常。 但是,如果方法名称不同,则可以使用method属性(如下一个示例所示)。 以下示例显示了具有两个不同方法名称的相同示例:spring-doc.cadn.net.cn

public class Something {
    public String doSomething(String str, Map m);

    public String doSomethingElse(String str);
}

以下示例演示如何使用method属性来指示映射:spring-doc.cadn.net.cn

<int:service-activator input-channel="input" output-channel="output" method="doSomethingElse">
    <bean class="org.bar.Foo"/>
</int:service-activator>

由于配置显式地将doSomethingElse方法,我们已经消除了歧义。spring-doc.cadn.net.cn