Apache Camel - 快速指南


Apache Camel - 简介

考虑这样一种情况:您所在城镇的一家大型在线杂货店(例如印度的 Bigbasket)邀请您为他们设计 IT 解决方案。稳定且可扩展的解决方案将帮助他们克服当今面临的软件维护问题。这家网上商店在过去十年里一直在经营业务。该商店接受客户对不同类别产品的在线订单,并将其分发给各自的供应商。例如,假设您订购了一些肥皂、油和牛奶;这三件物品将分别分发给三个供应商。然后,三个供应商将把他们的物资发送到一个共同的配送点,整个订单将由配送中心完成。现在,让我们看看他们今天面临的问题。

当这家商店开始营业时,它接受以逗号分隔的纯文本文件形式的订单。一段时间后,商店改用消息驱动下单。后来,一些软件开发人员建议采用基于 XML 的订单放置方式。最终,该商店甚至采用了网络服务界面。现在,真正的问题来了。现在订单有不同的格式。显然,公司每次升级接单格式时,都不想破坏之前部署的界面,以免造成客户心里的混乱。

与此同时,随着业务的不断增长,商店定期增加新的供应商。每个这样的供应商都有自己的接受订单协议。我们再次面临整合问题;我们的应用程序架构必须具有可扩展性,以适应新供应商及其独特的下单机制。

整个情况如下图所示 -

应用架构

现在,让我们看看 Apache Camel 如何为您提供帮助,为所描述的场景提供优雅、可维护、可扩展的解决方案架构。

在继续解决问题之前,我们需要做一个小假设。对于本教程中的所有讨论,我们将假设在线订单以 XML 格式放置。我们将在整个讨论中使用的订单文件的典型格式如下所示 -

<?xml version = "1.0" encoding = "UTF-8"?>
<OrderID Order = "001">
   <order product = "soaps">
      <items>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Original</Type>
            <Quantity>4</Quantity>
            <Price>25</Price>
         </item>
         <item>
            <Brand>Cinthol</Brand>
            <Type>Lime</Type>
            <Quantity>6</Quantity>
            <Price>30</Price>
         </item>
      </items>
   </order>
   
   <order product = "Oil">
      <items>
         <item>
            <Brand>Saffola</Brand>
            <Type>Gold</Type>
            <Quantity>2</Quantity>
            <Price>649</Price>
         </item>
         <item>
            <Brand>Fortune</Brand>
            <Type>Sunlite</Type>
            <Quantity>1</Quantity>
            <Price>525</Price>
         </item>
      </items>
   </order>
   
   <order product = "Milk">
      <items>
         <item>
            <Product>Milk</Product>
            <Brand>Amul</Brand>
            <Type>Pure</Type>
            <Quantity>2</Quantity>
            <Price>60</Price>
         </item>
      </items>
   </order>
</OrderID>

我们将使用上面的 XML 模板来说明本教程中的 Camel 示例。

Apache Camel - 概述

Camel 是一个黑匣子,它从某个端点接收消息并将其发送到另一个端点。在黑匣子内,消息可以被处理或简单地重定向。

Camel留言箱

那么为什么要为此建立一个框架呢?在实际情况中,如介绍案例研究中所示,可能有许多发送者和许多接收者,每个发送者和接收者都遵循自己的协议,例如 ftp、http 和 jms。系统可能需要许多复杂的规则,例如来自发送者 A 的消息只能传递给 B 和 C。在某些情况下,您可能必须将消息转换为接收者期望的另一种格式。此翻译可能会受到基于消息内容的某些条件的影响。因此,本质上您可能需要在协议之间进行转换、将组件粘合在一起、定义路由规则并提供基于消息内容的过滤。如下图所示 -

Camel框架

为了满足上述要求并为许多此类情况设计适当的软件架构,Gregor Hohpe 和 Bobby Woolf 在 2003 年记录了企业集成模式 ( EIP )。Apache Camel 提供了这些模式的实现,本教程的目的是教授您将了解如何在简介中描述的情况下使用 Camel。

Apache Camel 是一个开源框架。它是一个面向消息的中间件,提供基于规则的路由和中介引擎。您可以定义规则,例如如果是“牛奶”订单,则将其重定向到牛奶供应商;如果是“油”订单,则将其重定向到油供应商,等等。使用 Camel,您将能够实现这些规则并以熟悉的 Java 代码进行路由。这意味着您可以使用熟悉的 Java IDE 在类型安全的环境中定义这些规则。我们不需要使用 XML 配置文件,因为 XML 配置文件通常很庞大。如果您更喜欢使用 XML 来配置规则,Camel 虽然可以通过 Spring 框架支持 XML 配置。如果您是 Scala 爱好者,您甚至可以使用 Blueprint XML 配置文件甚至 Scala DSL。这也意味着您可以使用您最喜欢的 Java、Scala IDE 甚至简单的 XML 编辑器来配置规则。

该引擎的输入可以是逗号分隔的文本文件、POJO(普通旧 Java 对象)、XML 以及 Camel 支持的其他几种格式中的任何一种。同样,引擎的输出可以重定向到文件、消息队列甚至监视器屏幕,以便您查看发送到各个供应商的订单。这些称为端点,Camel 支持消息端点EIP 模式。Camel 端点将在端点章节稍后讨论。

Camel 通常与Apache ServiceMixApache ActiveMQApache CXF一起使用来实现面向服务的架构。

Apache Camel - 功能

了解了 Apache Camel 的概述后,现在让我们深入研究它的功能,看看它提供了什么。我们已经知道 Apache Camel 是一个开源 Java 框架,本质上提供了各种 EIP 的实现。Camel 通过提供与多种传输和 API 的连接,使集成变得更加容易。例如,您可以轻松地将 JMS 路由到 JSON、JSON 路由到 JMS、HTTP 路由到 JMS、FTP 路由到 JMS,甚至 HTTP 路由到 HTTP,以及连接到微服务。您只需在两端提供适当的端点即可。Camel 是可扩展的,因此将来可以轻松地将更多端点添加到框架中。

要将 EIP 和传输连接在一起,您可以使用领域特定语言 (DSL),例如 Java、Scala 和 Groovy。典型的 Java 路由规则可能如下所示:

from ("file:/order").to("jms:orderQueue");

此路由规则从订单目录加载文件,使用文件内容创建 JMS 消息,并将该消息发送到名为orderQueue的队列。

以下是 Camel 的一些最重要的功能,您会发现它们在开发 Camel 应用程序时非常有用 -

  • Camel 支持用于此类消息转换的可插入数据格式和类型转换器,因此将来可以添加新的格式和转换器。目前,它支持多种流行的格式和转换器;仅举几例 - CSV、EDI、JAXB、JSON、XmlBeans、XStream、Flatpack、Zip。

  • Camel 支持可插入语言在 DSL 中编写谓词。一些受支持的语言包括 JavaScript、Groovy、Python、PHP、Ruby、SQL、XPath、XQuery。

  • Camel 支持 POJO 模型,以便您可以在不同的点插入 Javabean。

  • Camel 通过使用消息传递来简化此类大型分布式异步系统的测试。

现在让我们了解Camel的架构,看看各种功能是如何实现的。

Apache Camel - 架构

Camel 架构由三个组件组成:集成引擎和路由器、处理器和组件。如下图所示 -

Camel架构

Camel 核心本身非常小,包含 13 个基本组件。其余 80 多个组件位于核心之外。这有助于保持对部署位置的低依赖性并促进未来的扩展。组件模块提供了与外部世界的端点接口。Endpoints 由 URI 指定,例如您在上一章中看到的file:/orderjms:orderQueue 。

处理器模块用于操纵和调解端点之间的消息我之前提到的EIP都是在这个模块中实现的。它目前支持EIP 书中记录的 40 多种模式和其他有用的处理单元。

处理器和端点使用 DSL 在集成引擎和路由器模块中连接在一起。连接这些时,您可以使用过滤器根据用户定义的条件过滤消息​​。如前所述,您在编写这些规则时有多种选择。为此,您可以使用 Java、Scala、Groovy 甚至 XML。

现在,我们来到 Camel 最重要的组件,可以将其视为核心 - CamelContext

Apache Camel - CamelContext

CamelContext提供对 Camel 中所有其他服务的访问,如下图所示 -

Camel上下文

让我们看看各种服务。默认情况下, Registry模块是一个 JNDI 注册表,保存应用程序使用的各种 Javabean 的名称。如果您将 Camel 与 Spring 一起使用,这将是 Spring ApplicationContext。如果你在 OSGI 容器中使用 Camel,这将是OSGI 注册表。顾名思义,类型转换器包含各种加载的类型转换器,它们将您的输入从一种格式转换为另一种格式您可以使用内置类型转换器或提供您自己的转换机制。组件模块包含您的应用程序使用组件。这些组件是通过自动发现加载到您指定的类路径上的。对于 OSGI 容器,只要激活新包,就会加载这些容器。我们已经在前面的章节中讨论了端点路由。数据格式模块包含加载的数据格式,最后语言模块表示加载的语言。

这里的代码片段将让您了解如何在 Camel 应用程序中创建CamelContext -

CamelContext context = new DefaultCamelContext();
try {
   context.addRoutes(new RouteBuilder() {
      // Configure filters and routes
   }
}
);

DefaultCamelContext类提供了CamelContext的具体实现。在addRoutes方法中,我们创建RouteBuilder的匿名实例。您可以创建多个RouteBuilder实例来定义多个路由。同一上下文中的每个路由必须有唯一的 ID。可以在运行时动态添加路由。与之前定义的 ID 相同的路由将替换旧路由。

接下来描述RouteBuilder实例内部的内容。

路线

路由器定义将消息从某个位置移动到某个位置的规则。您可以使用RouteBuilder在 Java DSL 中定义路由。您可以通过扩展内置RouteBuilder类来创建路线。该路线以起始端点开始,并以一个或多个终点结束。在两者之间,您实现处理逻辑。您可以在单个配置方法中配置任意数量的路由。

这是如何创建路线的典型示例 -

context.addRoutes(new RouteBuilder() {
   @Override
   public void configure() throws Exception {
      from("direct:DistributeOrderDSL")
      .to("stream:out");
   }
}

我们重写RouteBuilder类的configure方法并在其中实现我们的路由和过滤机制。在当前情况下,我们将从 Endpoint DistributeOrderDSL接收的输入重定向到控制台,该控制台由 Endpoint stream:out指定。

语言选择

您可以用不同的语言创建路线。以下是如何用三种不同语言定义相同路线的一些示例 -

JavaDSL

from ("file:/order").to("jms:orderQueue");

Spring DSL

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

斯卡拉DSL

from "file:/order" -> "jms:orderQueue"

过滤器

您使用过滤器来选择输入内容的一部分。要设置过滤器,您可以使用任意谓词实现。然后,过滤后的输入将发送到您所需的目标端点。在此示例中,我们过滤掉肥皂的所有订单,以便将这些订单集中发送给肥皂供应商。

from("direct:DistributeOrderDSL")
   .split(xpath("//order[@product = 'soaps']/items"))
      .to("stream:out");

在示例中,我们使用xpath谓词进行过滤。如果您更喜欢使用 Java 类进行过滤,请使用以下代码 -

from("direct:DistributeOrderDSL")
   .filter()
      .method(new Order(),"filter")
         .to("stream:out");

Order是您的自定义 Java 类具有您自己的过滤机制。

您可以在单个路由中组合多个谓词,如下所示 -

from("direct:DistributeOrderDSL")
   .choice()
      .when(header("order").isEqualTo("oil"))
         .to("direct:oil")
      .when(header("order").isEqualTo("milk"))
         .to("direct:milk")
      .otherwise()
         .to("direct:d");

因此,现在所有“石油”订单将发送给石油供应商,“牛奶”订单将发送给牛奶供应商,其余订单将发送给公共池。

定制处理器

您还可以使用自定义处理。下面的示例创建一个名为myCustomProcessor的自定义处理器,并在路由构建器中使用它。

Processor myCustomProcessor = new Processor() {
   public void process(Exchange exchange) {
      // implement your custom processing
   }
};
RouteBuilder builder = new RouteBuilder() {
   public void configure() {
      from("direct:DistributeOrderDSL")
      .process(myProcessor);
   }
};

您可以使用自定义处理器以及选择和过滤来更好地控制您的中介和路由 -

from("direct:DistributeOrderDSL")
   .filter(header("order").isEqualTo("milk"))
      .process(myProcessor);

使用XML

如果您愿意,可以使用更庞大的 XML 来定义路由。以下 XML 片段展示了如何通过 Spring XML 创建路由以及一些过滤 -

<camelContext xmlns = "http://camel.apache.org/schema/spring">
   <route>
      <from uri = "direct:DistributeOrderXML"/>
      <log message = "Split by Distribute Order"/>
      <split>
         <xpath>//order[@product = 'Oil']/items</xpath>
         <to uri = "file:src/main/resources/order/"/>
         <to uri = "stream:out"/>
      </split>
   </route>
</camelContext>

了解了如何构建路由后,我们现在将了解创建端点的各种技术。

Apache Camel - 端点

我们已经了解了集成代码中端点的样子。到目前为止我们使用的表达式(例如file:/order、jms:orderQueue、direct:distributeOrderDSL)是端点。如您所见,它们遵循 URI 规范格式。在评估此 URI 时,CamelContext创建Endpoint实例;您无需担心在 DSL 中实例化Endpoint实现。

以我们之前的示例为例,您可以在 Java DSL 中指定端点,如下所示 -

from ("file:/order").to("jms:orderQueue");

在春天,就像这里一样 -

<route>
   <from uri = "file:/order"/>
   <to uri = "jms:orderQueue"/>
</route>

在这两种情况下,端点都是常量字符串。在某些情况下,您可能希望在运行时构建此字符串。您可以使用 Java字符串格式化程序方法来完成此操作。Camel 提供了另一种更简单的方法来在运行时创建这些 URI 字符串。为此,Camel 提供了fromFtoF方法,它们接受带有用户指定参数的参数。以下语句说明了toF方法的使用-

from("direct:distributeOrderDSL”).toF("file://%s?fileName=%s", path, name);

由于有了这些方法,就不再需要使用 Java 内置字符串格式化程序方法。

Camel默认使用简单语言来计算端点表达式。Simple语言的设计主要是为了评估表达式谓词而不用太担心XPath的复杂性。为了评估谓词,您可以将其他语言(例如xpath)与默认的简单语言结合起来。这是通过使用加号分隔其他语言来完成的。这里的代码片段展示了如何将xpath字符串连接到Simple中编写的表达式。

from("direct:start")
.toD("jms:${orderQueue}+language:xpath:/order/@id");

Spring中,您可以实现与这里相同的效果 -

<route>
   <from uri = "direct:start"/>
   <toD uri = "jms:${orderQueue}+language:xpath:/order/@id"/>
</route>

您可以根据需要连接任意多种语言,每种语言与前一种语言之间用加号分隔。可以在此处找到支持的语言列表。

Apache Camel - 组件

Camel 提供了几个预构建的组件。

在本章中,我们将讨论camel-core模块中的一些重要组件。

Bean组件将beans绑定到 Camel 消息交换。创建 Endpoint 的 URI 指定为bean:beanID,其中beanID是在注册表中指定的 bean 名称。

JndiContext jndiContext = new JndiContext();
jndiContext.bind("MilkOrder", new MilkOrderProcessor());
CamelContext camelContext = new DefaultCamelContext(jndiContext);

camelContext.addRoutes(new RouteBuilder() {
   public void configure() {
      from("direct:bigBasket")
         .to("bean:MilkOrder?method=placeOrder");
   }
});

请注意如何使用bean:协议指定端点。您可以选择指定要调用的 bean 方法;在这种情况下,在计算 Endpoint 表达式时将调用名为placeOrder的方法。MilkOrder是MilkOrderProcessor Javabean的 JNDI 名称,代码片段的前两行中注册。为了简洁起见,这里省略了MilkOrderProcessor本身的定义。

直接的

您一定已经注意到我们前面的示例中使用了Direct。为了向石油供应商发送订单,我们在端点规范中使用direct:oil 。使用Direct组件允许您同步调用端点。我们之前的示例中的以下两个代码片段说明了Direct的使用-

.when(header("order").isEqualTo("oil"))
   .to("direct:oil")

和,

from("direct:DistributeOrderDSL")
   .process(myProcessor);

文件

文件组件提供对计算机上的文件系统的访问使用此组件,您将能够将来自其他组件的消息保存到本地磁盘。此外,它还允许其他Camel组件处理本地文件。使用文件组件时,您可以使用file:directoryName[?options]file://directoryName[?options]作为 URI 格式。您之前已经看到过该组件的用法 -

from ("file:/order").to("jms:orderQueue");

请注意,文件组件默认采用目录名称。因此,订单目录的内容将作为输入内容。要指定订单目录中的特定文件,您将使用以下语句 -

from ("file:/order?fileName = order.xml").to("jms:orderQueue");

日志

日志组件允许您将消息记录到底层日志机制。Camel 使用 Simple Logging Facade for Java (SLF4J) 作为各种日志框架的抽象。您可以使用java.util.logging、logback、log4j进行日志记录。此代码片段说明了日志组件的使用-

from("direct:DistributeOrderDSL")
   .to("bean:MilkOrder?method = placeOrder")
   .to("log:com.example.com?level = INFO&showBody = true");

SEDA

SEDA组件允许您异步调用同一CamelContext中的另一个端点。如果要跨CamelContext实例调用,则需要使用VM组件。SEDA 的使用如下所示 -

from("direct:DistributeOrderDSL")
// send it to the seda queue that is async
   .to("seda:nextOrder")

在此路由中,我们将简单地将订单路由到nextOrder异步队列。订阅该队列的客户端将从该队列中获取消息。

计时器

Timer组件用于定期发送消息,因此在测试 Camel 应用程序时非常有用。这里的代码片段每两秒向控制台发出一条测试消息 -

from("timer://testTimer?period = 2000")
   .setBody()
   .simple("This is a test message ${header.timer}")
      .to("stream:out");

Apache Camel - 消息队列

大多数集成项目都使用消息传递,因为它有助于创建松散耦合的应用程序体系结构。消息传递可以是同步的,也可以是异步的。JMS 支持点对点发布-订阅模型。您可以使用队列来实现点对点,使用主题来实现发布-订阅模型。在 Java 平台上,JMS - Java 消息传递服务提供到消息传递服务器的接口。Apache activeMQ 就是这样的开源 JMS 提供商之一。Camel 不附带 JMS 提供者;但是,可以将其配置为使用 activeMQ。要使用此组件,您需要在项目中包含以下 jar - activemq、camel-spring 和camel-jms。

以下代码片段展示了如何为 activeMQ 配置 Camel。

<bean id = "jms" class = "org.apache.camel.component.jms.JmsComponent">
   <property name = "connectionFactory">
      <bean class="org.apache.activemq.ActiveMQConnectionFactory">
         <property name = "orderQueue" value = "tcp://localhost:61000" />
      </bean>
   </property>
</bean>

在这里,Camel 应用程序将开始监听一个名为orderQueue的队列。队列本身是在本地主机上运行的 activeMQ 消息传递服务器中设置的,并列出端口 61000。完成此操作后,您的应用程序可以从应用程序中定义的任何端点向此队列发送或接收消息。

最后,现在是将所有内容放在一个项目中,以更深入地了解 Camel 应用程序是如何创建的。

Apache Camel - 项目

我们将使用 Maven 构建 Camel 项目。不过,我们更喜欢使用 IntelliJ IDE 进行开发。您可以为此项目使用您选择的任何 IDE。

创建新项目

创建一个新的Maven项目并指定以下内容 -

GroupId: Basket
ArtifactId: Basket

选择项目的默认位置,或者如果您愿意指定您选择的目录。

添加依赖项

您需要添加一些依赖项才能使用 Camel。依赖项添加到pom.xml中。因此,打开 pom.xml 并添加以下两个依赖项 -

<dependencies>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-core</artifactId>
      <version>2.20.0</version>
   </dependency>
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-stream</artifactId>
      <version>2.20.0</version>
   </dependency>
</dependencies>

注意- 我们的应用程序需要最低限度的依赖关系。当您使用其库中的更多 Camel 组件时,您将需要在此 pom.xml 文件中添加相应的依赖项。

创建 Java DSL

接下来,您将在 Java DSL 中编写过滤和路由代码。创建一个名为DistributeOrderDSL的新 Java 类。添加以下代码 -

public class DistributeOrderDSL {
   public static void main(String[] args) throws Exception {
      CamelContext context = new DefaultCamelContext();
      try {
         context.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
               from("direct:DistributeOrderDSL")
                  .split(xpath("//order[@product='soaps']/items")).to("stream:out");
               
               // .to("file:src/main/resources/order/");
            }
         });
         context.start();
         ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);
      } finally {
         context.stop();
      }
   }
}

main方法中,首先我们通过实例化DefaultCamelContext类中提供的默认实现来创建CamelContext

CamelContext context = new DefaultCamelContext();

接下来,我们通过创建匿名RouteBuilder实例来添加路由-

context.addRoutes(new RouteBuilder() {

我们重写配置方法以添加从直接 URI DistributeOrderDSL到系统控制台的路由。我们通过使用 xpath 查询提供一些过滤。

public void configure() throws Exception {
   from("direct:DistributeOrderDSL")
      .split(xpath("//order[@product = 'soaps']/items")).to("stream:out");
   // .to("file:src/main/resources/order/");
}

添加路线后,我们启动上下文 -

context.start();

接下来,我们添加用于创建直接 URI - DistributeOrderDSL的代码。

ProducerTemplate orderProducerTemplate = context.createProducerTemplate();
InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
   .getResource("order.xml").getFile());

最后,我们开始处理 -

orderProducerTemplate.sendBody("direct:DistributeOrderDSL", orderInputStream);

现在,当您的 Java DSL 代码完成后,测试应用程序之前剩下的唯一事情就是将order.xml文件添加到您的项目中。为此,您可以使用简介一章中显示的示例 XML。

检测结果

当您运行该应用程序时,您将看到以下输出 -

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

请注意,此处仅列出肥皂的订单。如果您希望将其存储到本地文件,只需注释stream.out行并在配置方法中取消注释以下行-

// .to("file:src/main/resources/order/");

在接下来的部分中,我们将学习如何将 Camel 与 Spring 结合使用。

Apache Camel - 与 Spring 一起使用

现在,我们将使用 Spring 重新创建上一章中的应用程序。这将使我们了解如何在 XML 而不是 DSL 中创建 Camel 路由。

创建新项目

创建一个新的Maven项目并指定以下内容 -

GroupId: BasketWithSpring
ArtifactId: BasketWithSpring

选择项目的默认位置,或者如果您愿意指定您选择的目录。

添加依赖项

除了在早期应用程序中使用的核心依赖项之外,您还需要添加更多依赖项才能使用 Spring。依赖项添加到 pom.xml 中。现在,打开 pom.xml 并添加以下依赖项 -

<dependencies>
   ...
   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.3.RELEASE</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.2</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.activemq</groupId>
      <artifactId>activemq-pool</artifactId>
      <version>5.15.1</version>
   </dependency>
   
   <dependency>
      <groupId>org.apache.camel</groupId>
      <artifactId>camel-spring</artifactId>
      <version>2.15.1</version>
   </dependency>
</dependencies>

为 Spring 创建 Java DSL

现在让我们创建一个名为DistributeOrderXML的新 Java 类。添加以下代码 -

public class DistributeOrderXML {
   public static void main(String[] args) throws Exception {
      ApplicationContext appContext = new ClassPathXmlApplicationContext(
         "SpringRouteContext.xml");
      CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);
      try {
         camelContext.start();
         ProducerTemplate orderProducerTemplate = camelContext.createProducerTemplate();
         InputStream orderInputStream = new FileInputStream(ClassLoader.getSystemClassLoader()
            .getResource("order.xml").getFile());
         
         orderProducerTemplate.sendBody("direct:DistributeOrderXML", orderInputStream);
      } finally {
         camelContext.stop();
      }
   }
}

main方法中,首先我们创建一个ApplicationContext实例,它是 Spring 应用程序中的中心接口。在其构造函数中,我们指定包含路由和过滤信息的 XML 文件的名称。

ApplicationContext appContext = new ClassPathXmlApplicationContext(
   "SpringRouteContext.xml");

接下来,我们创建CamelContext,并在其参数中指定上面创建的ApplicationContext

CamelContext camelContext = SpringCamelContext.springCamelContext(appContext, false);

至此,我们的路由和过滤就设置好了。因此,我们使用CamelContext的start方法来启动它。与前面的情况一样,我们定义用于加载 order.xml 文件的端点并开始处理。现在,让我们了解如何在 XML 中定义路由。

创建应用程序上下文

将新的 XML 文件添加到项目中并将其命名为SpringRouteContext.xml。将以下内容剪切并粘贴到此文件中。

<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
      http://camel.apache.org/schema/spring
      http://camel.apache.org/schema/spring/camel-spring.xsd ">
   <camelContext xmlns = "http://camel.apache.org/schema/spring">
      <route>
         <from uri = "direct:DistributeOrderXML"/>
         <log message = "Split by Distribute Order"/>
         <split>
            <xpath>//order[@product = 'Oil']/items</xpath>
            <to uri = "file:src/main/resources/order/"/>
            <to uri = "stream:out"/>
         </split>
      </route>
   </camelContext>
</beans>

在这里,我们定义 xpath 查询如下,请注意,我们现在选择“oil”的所有订单。

<xpath>//order[@product = 'Oil']/items</xpath>

输出端点有多个。第一个端点指定订单文件夹,第二个端点指定控制台。

<to uri = "file:src/main/resources/order/"/>
<to uri = "stream:out"/>

运行应用程序。

检测结果

运行该应用程序时,您将在屏幕上看到以下输出。

<items>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Original</Type>
      <Quantity>4</Quantity>
      <Price>25</Price>
   </item>
   <item>
      <Brand>Cinthol</Brand>
      <Type>Lime</Type>
      <Quantity>6</Quantity>
      <Price>30</Price>
   </item>
</items>

查看您指定路径下的订单文件夹。您将发现一个新创建的文件,其中包含上述 XML 代码。

结论

Camel 提供了一个可实现 EIP 的即用型框架,以简化您的集成项目。它支持使用特定于领域的语言进行编码以及使用 XML。