架构

CamelContext

师成师成· 更新于 2026-09-28· 阅读 23 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

CamelContext

CamelContext 是运行时系统,它将 Apache Camel 的所有基本概念(路由、端点、组件等)组织在一起。

这个上下文对象代表 Camel 运行时系统。通常,一个应用程序中只有一个 CamelContext 实例。

image

CamelContext 提供了对许多功能和服务的访问,其中最值得注意的有组件、类型转换器、注册表、端点、路由、数据格式和语言。

下表列出了 CamelContext 提供的最常用服务:

服务描述
组件包含所使用的组件。
端点包含已经使用过的端点。
路由正在使用的路由。
数据格式包含已加载的数据格式。
语言包含已加载的语言。
类型转换器包含已加载的类型转换器。Camel 提供了一种机制,允许你手动或自动地将一种类型转换为另一种类型。
注册表包含一个注册表,允许你查找 bean。

CamelContext 基础入门

为了让你更好地理解 Apache Camel,我们将讨论 CamelContext 内部包含的内容。

路由引擎

Camel 的路由引擎在底层传递消息,并承担所有繁重的工作,以确保消息被正确路由。它不会暴露给开发者,但你应该知道它的存在。

路由

路由是 Camel 的核心抽象。定义路由最简单的方式是将其描述为一系列处理器的链。在消息应用中使用路由有很多原因。通过将客户端与服务器、生产者与消费者解耦,路由可以做到以下几点:

  • 动态决定客户端将调用哪个服务器
  • 提供灵活的方式来添加额外的处理
  • 允许客户端和服务器独立开发
  • 通过将各司其职的不同系统连接起来,促进更好的设计实践
  • 允许对服务器的客户端进行桩替换(使用 mock),以便进行测试

Camel 中的每条路由都有唯一标识符。你可以使用该标识符来进行日志记录、调试、监控以及启动和停止路由。

路由有且只有一个消息输入源。它们实际上绑定到一个输入端点。

领域特定语言(DSL)

为了将处理器和端点连接在一起形成路由,Camel 定义了一种 DSL。

在基于 Java 的 Camel 中,DSL 意味着一个流式 Java API,其中的方法以 EIP 术语命名。Camel 提供了多种 DSL 语言。你也可以使用 XML 和 YAML DSL 来定义同一条路由。

在这里,你只需一条 Java 语句,就能定义一条从 file 端点消费文件的路由。Camel 使用 Filter EIP,通过 XPath 谓词来判断消息是否不是测试订单,从而对消息进行路由。如果消息通过测试,Camel 会将其转发到 JMS 端点。未通过过滤测试的消息将被跳过。

  • Java
  • XML
  • YAML
from("file:data/inbox")
    .filter().xpath("/order[not(@test)]")
        .to("jms:queue:order");
<route>
    <from uri="file:data/inbox"/>
    <filter>
        <xpath>/order[not(@test)]</xpath>
        <to uri="jms:queue:order"/>
    </filter>
</route>
- route:
    from:
      uri: file:data/inbox
      steps:
        - filter:
            expression:
              xpath:
                expression: "/order[not(@test)]"
            steps:
              - to:
                  uri: jms:queue:order

DSL 为 Camel 用户构建应用提供了一种良好的抽象。不过在底层,路由是由一个处理器(processor)图组成的。

处理器

处理器是 Camel 的核心概念,代表一个能够使用、创建或修改传入交换(Exchange)的节点。

在路由过程中,交换在各个处理器之间流动;因此,你可以把路由看作一个图,其中以各种专用处理器作为节点,用连线将一个处理器的输出连接到另一个处理器的输入。处理器可以是 EIP(企业集成模式)的实现、特定组件的生产者,也可以是你自己编写的代码。下图展示了处理器之间的消息流转。

image

路由以一个消费者(即 DSL 中的 from)开始,由它填充初始的交换。在每个处理器步骤中,上一步的输出(out)消息就是下一步的输入(in)消息。在许多情况下,处理器并不设置 out 消息,此时会重用 in 消息。交换的交换模式决定了在路由结束时是否需要向调用者返回回复。如果交换模式(MEP)为 InOnly,则不会返回任何回复;如果为 InOut,Camel 会取最后一步的 out 消息并将其返回。

Exchange(交换)

Exchange 是在路由中流动的消息容器。每当消费者接收到消息时,都会将其包装进一个 Exchange,并通过路由的处理器链发送。

Exchange 包含以下内容:

  • In 消息 —— 当前正在被处理的消息。大多数处理器直接读取并修改 In 消息。
  • 交换属性 —— 作用于该交换的元数据,类型为 Map<String, Object>。属性不会传播到外部系统,它们仅在路由内部可见。可以使用属性在同一路由的各处理器之间传递状态。
  • 异常 —— 在处理失败时设置。由错误处理器和异常子句用于确定如何处理该失败。

交换模式(MEP)决定了该交换是单向(InOnly)的还是请求-回复(InOut)的。对于 InOut,Camel 会将最终消息作为回复返回给调用者。

变量

变量(Variables)是路由过程中存储用户数据的推荐方式,可以替代交换属性。

Exchange 属性也会被 Camel 以及部分 EIP 和组件在内部使用,这可能导致命名冲突或意外行为。变量则完全供最终用户使用——Camel 绝不会在内部设置或读取你的变量。

变量可以在不同的层级进行作用域划分:

  • Exchange(默认)——当前交换私有,与 Exchange 属性相同,但不会与 Camel 内部实现产生命名冲突
  • Route——在特定路由的所有交换之间共享
  • Group——在一组命名路由之间共享
  • Global——在整个 CamelContext 之间共享

变量还可以通过 variableSend 和 variableReceive 选项与常用的 EIP(to、enrich、poll、unmarshal 等)集成,从而无需修改当前消息即可轻松从外部系统收集数据。

完整的参考文档请参阅变量。

消息

消息由三个部分组成:

  • Body(消息体)——即负载,可以是任意 Java 类型。Camel 的类型转换器系统会在需要时自动进行类型转换(例如,String 转 InputStream、JSON 转 POJO、byte[] 转 String)。
  • Headers(消息头)——一个 Map<String, Object> 形式的元数据。生产者和消费者会将消息头在内部与外部系统之间传递。例如,File 组件会设置 CamelFileName,HTTP 组件会映射 HTTP 头。Camel 内部使用的消息头以 Camel 为前缀。
  • Attachments(附件)——二进制附件(主要用于邮件和 SOAP 组件)。
消息头与 Exchange 属性是不同的。消息头随消息一起传递,可以发送到外部系统。Exchange 属性的作用范围限于路由,永远不会离开 Exchange。

组件

组件是 Camel 中的主要扩展点。

从编程角度来看,组件相当简单:它们与一个名称关联,该名称用于 URI 中,同时它们充当端点的工厂。

例如,FileComponent 在 URI 中通过 file 引用,它会创建 FileEndpoint。端点或许是 Camel 中更为基础的概念。

端点

端点是 Camel 的一种抽象,用于建模系统通过其发送或接收消息的通道末端。

image

在 Camel 中,你使用 URI 来配置端点,例如 file:data/inbox?delay=5000,并且也通过这种方式引用端点。在运行时,Camel 根据 URI 表示法查找端点。下图展示了其工作原理。

image

scheme(1)表示由哪个 Camel 组件处理该类型的端点。在此例中,file 这个 scheme 选择了 FileComponent。FileComponent 随后充当工厂,根据 URI 的其余部分创建 FileEndpoint。上下文路径 data/inbox(2)告诉 FileComponent 起始文件夹是 data/inbox。选项 delay=5000(3)表示应以 5 秒的间隔轮询文件。

下图展示了一个端点如何与交换(exchange)、生产者和消费者协同工作。

image

端点充当工厂,用于创建能够向特定端点接收和发送消息的消费者与生产者。

生产者

生产者(Producer)是 Camel 中的一种抽象,指代能够向端点发送消息的实体。当消息被发送到端点时,生产者负责处理使消息数据与该特定端点兼容的细节。例如,FileProducer 会将消息体写入 java.io.File。而 JmsProducer 会在将消息发送到 JMS 目的地之前,先把 Camel 消息映射为 jakarta.jms.Message。这是 Camel 的一个重要特性,因为它隐藏了与特定传输方式交互的复杂性。你只需要将消息路由到端点,繁重的工作由生产者来完成。

消费者

消费者(Consumer)是接收由某些外部系统产生的消息的服务,它将这些消息包装进一个交换,并发送它们去进行处理。消费者是 Apache Camel 中被路由交换的来源。要创建一个新的交换,消费者会使用包装所消费负载的端点。随后使用处理器通过路由引擎在 Camel 中发起该交换的路由。

Camel 有两种消费者:事件驱动消费者和轮询消费者(或称定时轮询消费者)。这些消费者之间的差异很重要,因为它们用于解决不同的问题。

事件驱动消费者

最常见的消费者是事件驱动消费者,如下所示:

image

这类消费者主要与客户端-服务器架构和 Web 服务相关。在 EIP(企业集成模式)领域,它也被称为异步接收器。事件驱动的消费者监听特定的消息通道,例如 TCP/IP 端口、JMS 队列、Twitter 账号、Amazon SQS 队列、WebSocket 等等,然后等待客户端向它发送消息。当消息到达时,消费者被唤醒并取出该消息进行处理。

轮询消费者 / 定时轮询消费者

与事件驱动的消费者相反,轮询消费者会主动去特定的来源(例如 FTP 服务器)获取消息。在 EIP 术语中,轮询消费者也被称为同步接收器,因为它在处理完当前消息之前不会继续轮询更多消息。轮询消费者的一种常见变体是定时轮询消费者,它按照预定的时间间隔进行轮询。File、FTP 和邮件组件都使用定时轮询消费者。

在 Camel 组件中,只使用事件驱动消费者或定时轮询消费者。非定时的轮询消费者仅用于按需轮询,例如使用 Poll Enrich EIP 时,或在 Java 中通过 Endpoint 的 createPollingConsumer() 方法创建 PollingConsumer 实例时使用。

启动顺序

CamelContext 启动时,会按照特定的顺序初始化服务:

  1. CamelContext — 初始化注册表、类型转换器和内部服务
  2. 组件 — 创建组件实例(或在首次使用时延迟加载)
  3. 端点 — 解析并创建路由所引用的端点
  4. 路由 — 将路由定义构建为处理器链
  5. 消费者 — 消费者最后启动,因此在任何消息流入之前,所有路由、端点和处理器都已完全就绪

这一顺序确保了当第一条消息到达时,它所需的一切都已初始化完毕。消费者最后启动非常重要——这可以防止消息在路由准备好处理它们之前就到达。

可以在运行时使用 CamelContext 或通过 JMX 单独启动和停止路由。

关于完整的生命周期细节(包括挂起/恢复和优雅关闭),请参阅 生命周期。

另请参阅

有关 Apache Camel 的高层架构信息,请参阅以下内容。

评论

登录后参与评论

正在加载评论…