Apache Camel 快速指南



Apache Camel - 简介

假设你所在城镇的一家大型在线杂货店,例如印度的 Bigbasket,邀请你为他们设计一个 IT 解决方案。这个稳定且可扩展的解决方案将帮助他们克服当前面临的软件维护问题。这家在线商店已经运营了十年。商店接受客户对不同类别产品的在线订单,并将这些订单分配给相应的供应商。例如,假设你订购了一些肥皂、油和牛奶;这三件商品将分别分配给三个相应的供应商。然后,这三个供应商将把他们的货物发送到一个共同的配送点,从那里由配送中心完成整个订单。

这家商店刚开始营业时,是通过逗号分隔的纯文本文件接收订单。一段时间后,商店转向了消息驱动的订单放置方式。后来,一些软件开发者建议使用基于 XML 的订单放置方式。最终,商店甚至采用了 Web 服务接口。现在,真正的难题出现了。订单现在采用不同的格式。显然,每次公司升级订单接受格式时,都不想破坏之前部署的接口,以免造成客户的混淆。

同时,随着业务不断增长,商店定期向其产品目录中添加新的供应商。每个供应商都有自己接受订单的协议。我们再次面临集成问题;我们的应用程序架构必须能够扩展以适应具有其独特订单放置机制的新供应商。

整个情况如下图所示:

Application Architecture

现在,让我们看看 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 Message Box

那么为什么要为此创建一个框架呢?在实际情况中,正如引言案例研究中所见,可能存在许多发送者和许多接收者,每个发送者和接收者都遵循其自身的协议,例如 ftp、http 和 jms。系统可能需要许多复杂的规则,例如来自发送者 A 的消息只能传递给 B 和 C。在某些情况下,你可能需要将消息转换为接收者期望的另一种格式。这种转换可能取决于消息内容的某些条件。因此,你本质上可能需要在协议之间进行转换、将组件粘合在一起、定义路由规则以及根据消息内容提供过滤。如下图所示:

Camel Framework

为了满足上述要求并为许多此类情况设计合适的软件架构,Gregor Hohpe 和 Bobby Woolf 在 2003 年编制了企业集成模式(EIP)。Apache Camel 提供了这些模式的实现,本教程的目的是教你如何在引言中描述的类似情况下使用 Camel。

Apache Camel 是一个开源框架。它是一个面向消息的中间件,提供基于规则的路由和中介引擎。你可以定义规则,例如,如果它是“牛奶”订单,则将其重定向到牛奶供应商;如果它是“油”订单,则将其重定向到油供应商,依此类推。使用 Camel,你将能够实现这些规则并在熟悉的 Java 代码中进行路由。这意味着你可以使用你熟悉的 Java IDE 在类型安全的环境中定义这些规则。我们不需要使用 XML 配置文件,这些文件通常很冗长。虽然 Camel 通过 Spring 框架支持 XML 配置,但如果你更喜欢使用 XML 来配置规则,也可以这样做。你甚至可以使用 Blueprint XML 配置文件,如果你是 Scala 爱好者,还可以使用 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");

此路由规则从 **order** 目录加载文件,使用文件的内容创建一个 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 Architecture

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

**处理器** 模块用于操作和中介端点之间的消息。前面提到的 EIP 在此模块中实现。它目前支持 40 多种模式,如EIP 书籍 和其他有用的处理单元中所述。

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

现在,我们来看 Camel 中最重要的组件,它可以被认为是核心——**CamelContext**。

Apache Camel - CamelContext

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

CamelContext

让我们来看看各种服务。默认情况下,注册表模块是一个 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 实例内部的内容。

路由

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

这是一个创建路由的典型示例:

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

我们覆盖RouteBuilder 类的 configure 方法,并在其中实现我们的路由和过滤机制。在本例中,我们将从端点DistributeOrderDSL接收到的输入重定向到控制台,该控制台由端点stream:out指定。

语言选择

您可以使用不同的语言创建路由。以下是一些如何在三种不同语言中定义相同路由的示例:

Java DSL

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

Spring DSL

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

Scala DSL

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

过滤器

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

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");

在 Spring 中,如下所示:

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

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

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

由于这些方法,无需使用 Java 内置的String格式化程序方法。

Camel 默认使用Simple语言来计算端点表达式。Simple语言主要用于评估表达式谓词,而无需过多考虑XPath 的复杂性。为了评估谓词,您可以将另一种语言(例如xpath)与默认的Simple语言结合使用。这是通过使用加号来分隔其他语言来完成的。此处的代码片段显示了如何将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

Bean组件将 bean 绑定到 Camel 消息交换。创建端点的 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 方法;在这种情况下,在评估端点表达式时将调用名为placeOrder 的方法。MilkOrder 是在代码片段的前两行注册的MilkOrderProcessor JavaBean 的 JNDI 名称。为了简洁起见,此处省略了MilkOrderProcessor本身的定义。

Direct

您必须注意到在我们之前的示例中使用了Direct。要将订单发送给石油供应商,我们在端点规范中使用了direct:oil。使用Direct组件允许您同步调用端点。我们之前示例中的以下两个代码片段说明了Direct 的用法:

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

以及:

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

File

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

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

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

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

Log

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

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

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

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

Apache Camel - 消息队列

大多数集成项目都使用消息传递,因为它有助于创建松散耦合的应用程序架构。消息传递可以是同步的或异步的。JMS 支持点对点发布-订阅模型。您可以对点对点使用Queue,对发布-订阅模型使用Topic。在 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://127.0.0.1:61000" />
      </bean>
   </property>
</bean>

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

最后,现在是时候将所有内容放在一个项目中,以便更深入地了解 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() {

我们覆盖configure方法以添加从直接 URIDistributeOrderDSL到系统控制台的路由。我们通过使用 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行,并在您的configure方法中取消注释以下行。

// .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);

此时,我们的路由和过滤已设置完毕。因此,我们使用其start方法启动CamelContext。与之前的案例一样,我们定义用于加载order.xml文件的Endpoint并启动处理。现在,让我们了解如何在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>

输出端点是多个。第一个端点指定order文件夹,第二个端点指定控制台。

<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>

检查您指定的路径中的order文件夹。您将找到一个新创建的文件,其中包含上述XML代码。

结论

Camel提供了一个现成的框架,该框架实现了EIP以简化您的集成项目。它支持使用领域特定语言以及使用XML。

广告