34.2. 消息
概述
消息对象使用以下抽象模型代表消息:
- 邮件正文
- 邮件标题
- 消息附加
消息正文和消息标题可以是任意类型(它们作为类型 对象
声明),邮件附件则声明为 type javax.activation.DataHandler
,它可以包含任意 MIME 类型。如果您需要获取消息内容的 concrete 表示,您可以使用类型转换器机制将正文和标头转换为另一类型,并可能使用 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 节 “Message Interface”。
Bazy create of bodies、headers 和 attachments
Apache Camel 支持创建 bodies、标头和附件。这意味着,在需要消息正文前,不会创建代表邮件正文、邮件标题或邮件附加的对象。
例如,请考虑以下访问 In 消息的 foo
message 标头的路由:
from("SourceURL") .filter(header("foo") .isEqualTo("bar")) .to("TargetURL");
在这个路由中,如果假设 SourceURL 引用的组件支持 lazy 创建,则不会实际解析 In 消息标头,直到执行 标头("foo")
调用为止。此时,底层消息实现会解析标头并填充标头映射。在到达路由末尾之前,消息正文 不会被解析,直到 进入到("TargetURL")
调用。此时,正文被转换为写入目标端点 TargetURL 所需的格式。
通过在填充正文、标头和附加前等待最后可能过长,您可以确保避免不必要的转换。在某些情况下,您可以完全避免解析。例如,如果路由没有明确引用消息标头,消息可以遍历路由,而无需解析标头。
实践中是否实施 lazy 创建是否取决于底层组件实施。通常,在创建消息正文、邮件标题或邮件附件时,lazy 创建非常宝贵。有关实现支持延迟创建的消息类型的详情,请参考 第 44.2 节 “实施消息接口”。
延迟创建消息 ID
Apache Camel 支持 lazy 创建消息 ID。也就是说,只有在您实际调用 getMessageId ()
方法时才会生成消息 ID。此方法的 DefaultExchange.getExchangeId ()
实现将 ID 生成委派给使用 CamelContext
注册的 UUID 生成器。
如果端点实施实施需要唯一消息 ID,则端点实施会调用 getMessageId ()
方法隐式。特别是,JMS 消息通常包含一个包含唯一消息 ID 的标头,因此 JMS 组件自动调用 getMessageId ()
来获取消息 ID (这由 JMS 端点上的 messageIdEnabled
选项控制)。
有关如何使用 CamelContext
注册 UUID 生成器的详情,请参考 第 34.4 节 “内置 UUID Generators”。
初始消息格式
In 消息的初始格式由源端点决定,而 Out 消息的初始格式由目标端点决定。如果底层组件支持 lazy 创建,则消息会保持未解析,直到应用程序明确访问为止。大部分 Apache Camel 组件以相对原始形式进行 创建消息正文,例如,使用 byte[]
等类型来代表消息正文,ByteBuffer
、InputStream
或 OutputStream
等类型。这样可确保创建初始消息所需的开销是最小的。在更详细的信息格式中,需要组件通常会依赖于 类型转换器或 marshalling 处理器。
类型转换器
这并不重要信息的初始格式,因为您可以使用内置类型转换器轻松将消息从一个格式转换为另一个格式(请参阅 第 34.3 节 “内置类型 Converters”)。在 Apache Camel API 中有一些方法公开类型转换功能。例如,可以将 convertBodyTo (Class 类型)
方法插入到路由中,以转换 In 消息的正文,如下所示:
from("SourceURL").convertBodyTo(String.class).to("TargetURL");
将 In 消息的正文转换为 java.lang.String
。以下示例演示了如何在 In message body 的末尾附加一个字符串:
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)
WWN-将消息正文返回为 type,T
。 -
getHeader (String name, Class<T> type)
WWN-ocpReturns named header 值为 type,T
。
有关支持的转换类型的完整列表,请参阅 第 34.3 节 “内置类型 Converters”。
转换为 XML
除了支持简单类型之间的转换(如 字节[]
、ByteBuffer
、String
等等),内置类型转换器还支持转换为 XML 格式。例如,您可以将消息正文转换为 org.w3c.dom.Document
类型。这个转换比简单的转换更昂贵,因为它涉及解析整个消息,然后创建节点树来代表 XML 文档结构。您可以转换为以下 XML 文档类型:
-
org.w3c.dom.Document
-
javax.xml.transform.sax.SAXSource
与更简单的转换相比,XML 类型转换的处理能力比较小。因为并非所有消息正文都符合 XML 结构,因此您必须记住此类型转换可能会失败。另一方面,在很多情况下,路由器只处理 XML 消息类型。
marshalling 和 unmarshalling
marshalling 涉及将高级别格式转换为低级格式,并且取消 汇总涉及将低级格式转换为高级别的格式。以下两个处理器用于在路由中执行 marshalling 或 unmarshalling:
-
marshal()
-
unmarshal()
例如,若要从文件中读取序列化 Java 对象,并将其解压缩到 Java 对象,您可以使用 例 34.3 “解封 Java 对象” 中显示的路由定义。
例 34.3. 解封 Java 对象
from("file://tmp/appfiles/serialized") .unmarshal() .serialization() .<FurtherProcessing> .to("TargetURL");
最终消息格式
当 In 消息到达路由末尾时,目标端点必须能够将消息正文转换为可写入物理端点的格式。同样的规则 也适用于 返回源端点的消息。此转换通常隐式执行,使用 Apache Camel 类型转换器。通常,这涉及从低级格式转换到另一个低级格式,例如从 字节[]
数组转换为 InputStream
类型。