34.2. 消息

概述

Message 对象使用以下抽象模型代表信息:

  • 邮件正文
  • Message headers
  • 消息附加

消息正文和消息标头可以是任意类型(它们被声明为类型 对象)并将消息附件声明为类型为 javax.activation.DataHandler,其中可以包含任意 MIME 类型。如果您需要获取消息内容的声明,您可以使用类型转换器机制将正文和标头转换为另一个类型,可能使用 marshalling 和 unmarshalling 机制。

Apache Camel 消息的一个重要功能是它们支持对消息正文和标头 的创建。在某些情况下,这意味着消息可以通过路由,而无需解析所有消息。

Message 接口

org.apache.camel.Message 接口定义了访问消息正文、消息标头和消息附加的方法,如 例 34.2 “消息接口” 所示。

例 34.2. 消息接口

// Access the message body
Object getBody();
<T> T  getBody(Class<T> type);
void   setBody(Object body);
<T> void setBody(Object body, Class<T> type);

// Access message headers
Object getHeader(String name);
<T> T  getHeader(String name, Class<T> type);
void   setHeader(String name, Object value);
Object removeHeader(String name);
Map<String, Object> getHeaders();
void setHeaders(Map<String, Object> headers);

// Access message attachments
javax.activation.DataHandler getAttachment(String id);
java.util.Map<String, javax.activation.DataHandler> getAttachments();
java.util.Set<String> getAttachmentNames();
void addAttachment(String id, javax.activation.DataHandler content)

// Access the message ID
String getMessageId();
void   setMessageId(String messageId);

有关消息接口方法的完整描述,请参阅 第 44.1 节 “消息接口”

lazy creation of bodies、headers 和 attachments

Apache Camel 支持创建正文、标头和附加内容。这意味着,代表邮件正文、邮件标题或消息附加的对象不会被创建,直到需要它们。

例如,请考虑以下路由,它从 In 消息访问 foo 邮件标头:

from("SourceURL")
    .filter(header("foo")
    .isEqualTo("bar"))
    .to("TargetURL");

在本路由中,如果假设 SourceURL 引用的组件支持 lazy 创建,In message 标头不会被实际解析,直到执行 header("foo") 调用为止。此时,底层消息实现会解析标头并填充标头映射。在到达路由结束前,邮件正文 不会在路由末尾(位于 ("TargetURL") 调用前解析。此时,正文将转换为写成目标端点 TargetURL 所需的格式。

在填充正文、标头和附加前等待最后一个可能的时间,您可以确保避免不必要的类型转换。在某些情况下,您可以完全避免解析。例如,如果路由没有对消息标头的显式引用,则消息可以在不需要解析标头的情况下遍历路由。

是否在实践中实施是否实施是否取决于底层组件的实施。通常,当创建消息正文、邮件标题或消息附件是代价昂贵的时,会非常宝贵的创建。有关实现支持延迟创建的消息类型的详情,请参考 第 44.2 节 “实施消息接口”

消息 ID 的 lazy 创建

Apache Camel 支持创建消息 ID。也就是说,只有在您实际调用 getMessageId() 方法时才会生成消息 ID。这个方法的 DefaultExchange.getExchangeId() 实现将 ID 生成委托给使用 CamelContext 注册的 UUID 生成器。

如果端点实施了需要唯一消息 ID 的协议,一些端点实施会隐式调用 getMessageId() 方法。特别是,JMS 消息通常包含一个包含唯一消息 ID 的标头,因此 JMS 组件会自动调用 getMessageId() 获取消息 ID(这由 JMS 端点上的 messageIdEnabled 选项控制)。

有关如何使用 CamelContext 注册 UUID 生成器的详情,请参考 第 34.4 节 “built-In UUID Generators”

初始消息格式

In 消息的初始格式由源端点决定,Out 消息的初始格式由目标端点决定。如果底层组件支持 lazy 创建,则该消息将保持不变,直到应用程序明确访问为止。大部分 Apache Camel 组件以相对的原始格式是:使用 byte[] 等类型(如 byte[]、ste BufferInputStreamOutputStream )创建消息正文。这样可确保创建初始信息所需的开销最小。当需要更协作的消息格式时,通常依赖于 类型转换器总结处理器

类型转换器

消息的初始格式无关紧要,因为您可以使用内置的类型转换器(请参阅 第 34.3 节 “内置(In Type Converters)”)轻松地将信息从一个格式转换为另一个格式(请参阅 )。Apache Camel API 中有多种方法可公开类型转换功能。例如,可以将 convertBodyTo(Class type) 方法插入路由中,以转换 In 消息的正文,如下所示:

from("SourceURL").convertBodyTo(String.class).to("TargetURL");

In 邮件的正文将转换为 java.lang.String。以下示例演示了如何在 In 消息正文末尾附加字符串:

from("SourceURL").setBody(bodyAs(String.class).append("My Special Signature")).to("TargetURL");

在将字符串附加到结尾前,将消息正文转换为字符串格式。本例中并不需要显式转换邮件正文。您还可以使用:

from("SourceURL").setBody(body().append("My Special Signature")).to("TargetURL");

其中 append() 方法会在附加参数前自动将消息正文转换为字符串。

消息中的类型转换方法

org.apache.camel.Message 接口会公开一些方法来明确执行类型转换:

  • getBody(Class<T> type) the message body as type, T.
  • getHeader(String name, Class<T> type) abrt-abrtRe returns named header value as type, T.

有关支持的转换类型的完整列表,请参阅 第 34.3 节 “内置(In Type Converters)”

转换为 XML

除了支持简单类型(如 byte[]steBufferString 等等),内置类型转换器还支持转换为 XML 格式。例如,您可以将消息正文转换为 org.w3c.dom.Document 类型。这个转换比简单转换更为昂贵,因为它涉及解析整个消息,然后创建一个节点来代表 XML 文档结构。您可以转换为以下 XML 文档类型:

  • org.w3c.dom.Document
  • javax.xml.transform.sax.SAXSource

XML 类型转换的适用性比更简单的转换更小。因为并非每个消息正文都符合 XML 结构,所以您必须记住这种类型转换可能会失败。另一方面,有许多路由器仅涉及 XML 消息类型。

marshalling 和 unmarshalling

摘要 涉及将高级别格式转换为低级格式,而 unmarshalling 涉及将低级格式转换为高级别格式。以下两个处理器用于在路由中执行摘要或解压缩:

  • marshal()
  • unmarshal()

例如,要从文件中读取序列化 Java 对象并将其解包到 Java 对象,您可以使用 例 34.3 “解包 Java 对象” 中显示的路由定义。

例 34.3. 解包 Java 对象

from("file://tmp/appfiles/serialized")
    .unmarshal()
    .serialization()
    .<FurtherProcessing>
    .to("TargetURL");

最终消息格式

In 消息到达路由末尾时,目标端点必须能够将消息正文转换为可写入物理端点的格式。同一规则适用于 注销 到达源端点的消息。这个转换通常是隐式执行,使用 Apache Camel 类型转换器。通常,这涉及从低级格式转换为另一个低级格式,例如从 byte[] 数组转换为 InputStream 类型。