开始
本文档将指导您了解 Apache Camel Core 的基础知识。在阅读完毕后,您将对系统集成有基本的了解,学习了该项目的一些最重要的概念,并能够创建和运行您的第一个项目。
企业集成模式(E.I.P.)书籍
关于设计模式的书籍记录了特定领域内的最佳实践。这些书籍的作者希望传播最佳实践的知识,并促进讨论架构设计的词汇。
一本关于设计模式的著名书籍是《企业集成模式:设计、构建和部署消息传递解决方案》,由 Gregor Hohpe 和 Bobby Wolf 撰写。这本被称为 E.I.P.的书描述了 65 种用于异步消息传递系统的设计模式。该书为每个模式都赋予了一个名称和一个图像,用于在架构图中使用。
支持文件
Apache Camel 的在线文档
右侧的链接可在指南中不同主题之间进行轻松导航。我们的文档试图涵盖新手和有经验的用户的主题。然而,有经验的用户可能想跳过他们熟悉的主题。
多年来,我们的社区已经撰写了关于 Apache Camel 的书籍、文章和教程。我们的社区还通过许多视频和演讲介绍了 Apache Camel。
一些来自会员开发的材料中的重要参考资料,可能对新用户提供重要帮助
-
《Camel 实战第二版》这本书目前被视为 Camel 的圣经,其中有一章是免费的,强烈推荐阅读,以便更加熟悉 Camel。 -
Apache Camel 培训的基础,由 Michael Hoffman 提供。
我们强烈建议我们的用户浏览上述页面,以寻找适合他们需求的额外材料。
创建您的第一个项目
我们将从创建一个简单的集成开始。您需要在系统上安装 Apache Maven 和 JDK 11 或更高版本。
|
生成项目
您将使用 Camel 提供的各种 Maven 原型来创建您的第一个项目。原型是项目的模板。换句话说,Camel Core 提供了可用于创建项目的模板。
运行此命令以创建您的第一个 Camel Core 项目:
mvn archetype:generate -B -DarchetypeGroupId=org.apache.camel.archetypes -DarchetypeArtifactId=camel-archetype-java -DarchetypeVersion=3.18.4 -Dpackage=org.apache.camel.learn -DgroupId=org.apache.camel.learn -DartifactId=first-camel-integration -Dversion=1.0.0-SNAPSHOT
如果您以前从未使用过原型,那么这个命令看起来很长。我们将解释相关的参数。
-
-DarchetypeArtifactId
:这是要使用的原型的 ID(即要使用的 Camel Core 模板之一 - 在这种情况下是camel-archetype-java
) -
-DarchetypeVersion
:这是要使用的原型版本。这也是用于示例的 Camel 版本。在这个示例中,我们使用3.18.4
。 -
-Dpackage
:您正在创建的项目的包名称。在本指南中,我们将使用org.apache.camel.learn
。 -
-DgroupId
:您正在创建的项目的组 ID。在本指南中,我们将使用org.apache.camel.learn
。 -
-DartifactId
:您正在创建的项目的工件名称。 -
您的项目的版本。
|
构建和运行项目
您可以运行以下命令来构建项目:
mvn clean package
要运行该项目,您可以运行以下命令:
mvn camel:run -Dcamel.main.durationMaxMessages=2
运行上述命令后,您应该看到以下信息:
...
[che.camel.learn.MainApp.main()] MainSupport INFO Apache Camel (Main) 3.18.4 is starting
[che.camel.learn.MainApp.main()] BaseMainSupport INFO Auto-configuration summary
[che.camel.learn.MainApp.main()] BaseMainSupport INFO [JVM System Property] camel.main.durationMaxMessages=2
[che.camel.learn.MainApp.main()] XPathBuilder INFO Created default XPathFactory com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl@33cc7a16
[che.camel.learn.MainApp.main()] FileEndpoint INFO Endpoint is configured with noop=true so forcing endpoint to be idempotent as well
[che.camel.learn.MainApp.main()] FileEndpoint INFO Using default memory based idempotent repository with cache max size: 1000
[che.camel.learn.MainApp.main()] AbstractCamelContext INFO Apache Camel 3.18.4 (camel-1) is starting
[che.camel.learn.MainApp.main()] AbstractCamelContext INFO Routes startup (started:1)
[che.camel.learn.MainApp.main()] AbstractCamelContext INFO Started route1 (file://src/data)
[che.camel.learn.MainApp.main()] AbstractCamelContext INFO Apache Camel 3.18.4 (camel-1) started in 89ms (build:12ms init:68ms start:9ms JVM-uptime:1s)
[che.camel.learn.MainApp.main()] MainSupport INFO Waiting until complete: Duration max 2 messages processed
[1) thread #1 - file://src/data] route1 INFO Other message
[1) thread #1 - file://src/data] route1 INFO UK message
[1) thread #1 - file://src/data] MainLifecycleStrategy INFO Duration max messages triggering shutdown of the JVM
[ CamelMainShutdownCamelContext] AbstractCamelContext INFO Apache Camel 3.18.4 (camel-1) is shutting down (timeout:45s)
[ CamelMainShutdownCamelContext] AbstractCamelContext INFO Routes stopped (stopped:1)
[ CamelMainShutdownCamelContext] AbstractCamelContext INFO Stopped route1 (file://src/data)
[ CamelMainShutdownCamelContext] AbstractCamelContext INFO Apache Camel 3.18.4 (camel-1) shutdown in 7ms (uptime:1s JVM-uptime:2s)
[che.camel.learn.MainApp.main()] MainSupport INFO Apache Camel (Main) 3.18.4 shutdown
如果您在终端上看到这样的输出,意味着集成运行良好。
您刚刚运行的集成消耗了两个文件,并根据它们的内容将它们复制到一个目录中。您可以自己查看,只需查看项目中的 target/messages
目录即可。
find target/messages
你应该有以下文件:
target/messages target/messages/others target/messages/others/message2.xml target/messages/uk target/messages/uk/message1.xml
|
理解项目
您创建的集成实现了一种模式(E.I.P.)称为基于内容的路由器。Camel 实现了这种模式,允许您根据消息的内容来实现路由逻辑。
更具体地说,这个集成会查看 src/data
目录中 XML 文件的内容。如果 city
元素的内容是伦敦,那么它将文件移动到 target/messages/uk
目录。否则,它将文件移动到 target/messages/others
目录。
为了创建执行此任务的集成,此代码配置了一个路由,将由地址 file:src/data?noop=true
表示的源端点连接到由地址 file:target/messages/uk
和 file:target/messages/others
表示的另外两个端点。
如果你对技术术语感到不知所措,不要担心。在接下来的部分中,我们将解释每个术语的含义以及为什么它们对基于 Camel 的集成很重要。
终点
当我们谈论进程间通信,比如客户端/服务器或微服务时,我们经常使用术语"端点"来指代一个软件实体。在这个上下文中,一个端点的特点是它可以通过地址进行联系。地址本身可能传达了端点的其他特征。例如,地址 host:port
传达了基于 TCP 的通信端点的端口和网络名称。
地址和该地址可联系的软件之间的区别通常不重要。
|
Camel 为许多通信技术实现的端点提供开箱即用的支持。以下是一些受支持的端点技术的示例:
-
一个 JMS 队列。
-
一个网络服务。
-
一个文件。文件可能听起来不像是一种可能的终点,直到你意识到在某些系统中,一个应用程序可能会将信息写入文件,然后另一个应用程序可能会读取该文件。 -
一个 FTP 服务器。
-
一个电子邮件地址。客户端可以向电子邮件地址发送消息,服务器可以从邮件服务器读取传入的消息。 -
一个 POJO(普通的旧 Java 对象)。
路线
在基于 Camel 的应用程序中,您创建路由。路由用于将源端点连接到目标端点。
|
一条路由描述了一个 Message
从源端点经过任意类型的决策流程(如过滤器和路由器),到达目标端点(如果有的话)的逐步移动。
|
在您创建的项目中,应该有 2 个源文件位于目录 src/main/java/org/apache/camel/learn
中:
-
MainApp.java
:包含配置和启动应用程序的代码。 -
MyRouteBuilder.java
:包含了路线的代码。
路线的代码应该是:
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
from("file:src/data?noop=true")
.choice()
.when(xpath("/person/city = 'London'"))
.log("UK message")
.to("file:target/messages/uk")
.otherwise()
.log("Other message")
.to("file:target/messages/others");
}
}
我们将在本指南的后面部分详细阐述骆驼核心项目中路由的性质和作用。现在,让我们专注于我们创建的路由的两个最重要的方面。
-
它扩展了RouteBuilder
,这是在 Camel 中创建路由的基类。 -
它使用configure
方法来描述数据从源到目的地的逐步移动。
路由配置
在这个路由配置中,我们将源端点(由地址 file:src/data?noop=true
表示)连接到另外两个端点(由地址 file:target/messages/uk
和 file:target/messages/others
表示)。在 Camel 中,统一资源标识符(URI)表示端点的地址。这些 URI 传达了对于路由和集成非常重要的附加信息。
-
用于消费和/或生产数据的组件。 -
资源标识符。
-
组件的选项。
骆驼广泛使用 URI 来允许您引用端点。
URL 的意思是统一资源定位符,URI 的意思是统一资源标识符,URN 的意思是统一资源名称
一些 Camel 方法接受一个 URI 字符串作为参数。人们通常知道 URI 是“类似于 URL 的东西”,但并不总是理解 URI 与 URL 之间的关系,或者与其他缩写诸如 IRI 和 URN 之间的关系。
大多数人熟悉 URL(统一资源定位符),例如 http://…
, ftp://…
, \mailto:…:
。URL 指定了资源的位置。
一个 URN 是不同“唯一标识符”方案的包装器。URN 的语法是 urn:<scheme-name>:<unique-identifier>
。URN 唯一标识一个资源(例如:书籍、人员或设备)。单独使用,URN 不指定资源的位置。
URI(统一资源标识符)是 URL 或 URN。
终端地址
在 Camel 中,表示端点地址的 URI 采用以下格式:
component:resource[?options]
URI 的 scheme 部分表示用于消费或生产数据的组件。Camel 包含超过 300 个组件,允许您的应用程序与许多系统、协议和应用程序进行通信。
这些是 Camel 的有效 URI 示例: jms:queue:order
, kafka:myTopic?groupId=KafkaConsumerFullIT
, direct:result
。通过查看这些 URI,我们可以确定它们使用了 jms
, kafka
和 direct
组件。
每个组件都有自己特定的功能、约束和要求,在使用它们时我们必须遵守。Camel 通过 resource
和 options
将它们暴露出来。这意味着根据我们正在使用的组件而有所不同。例如,在文件组件中,资源是一个目录;在 Kafka 组件中,资源是主题;等等。
路由配置和 EIPS
您创建的集成实现了一种模式(E.I.P.)称为基于内容的路由器。
骆驼通常通过 Java 领域特定语言(Java DSL)公开这些模式。您可以在路由中使用 Java DSL 中的方法来实现这些模式。例如,您创建的集成包含以下代码片段:
// ...
.choice()
.when(xpath("/person/city = 'London'"))
.log("UK message")
.to("file:target/messages/uk")
.otherwise()
.log("Other message")
.to("file:target/messages/others");
// ...
上面的代码通过评估一个谓词( when()
),该谓词测试消息体是否与 xpath 表达式( xpath("/person/city = 'London'")
)匹配,来实现基于内容的路由器。如果 true
,则消息的目标端点应为 file:target/messages/uk
。否则,目标端点应为 file:target/messages/others
。
Camel 支持 Gregor Hohpe 和 Bobby Woolf 的优秀书籍中的大多数企业集成模式。
添加路由并运行应用程序
在执行路由之前,需要对其进行配置并添加到 CamelContext 中。
MainApp.java
文件包含执行以下步骤的代码:
public class MainApp {
public static void main(String... args) throws Exception {
Main main = new Main();
main.configure().addRoutesBuilder(new MyRouteBuilder());
main.run(args);
}
}
我们首先创建一个主组件,配置它包含路由( main.configure().addRoutesBuilder(new MyRouteBuilder());
)。然后我们通过运行 run
方法来启动主应用程序,该方法将创建 CamelContext 并在前台执行集成,直到我们终止它(即使用 Ctrl + C
)。
在这个例子中,您不直接与 CamelContext 进行交互,但它是 Camel 的一个基本部分。我们将在下一节中讨论它。
CAMEL 的基本概念和术语
在本节中,我们解释了额外的 Camel 概念和特性。
骆驼上下文
CamelContext 是运行时系统,它将我们到目前为止介绍的所有基本概念(路由、端点、组件等)联系在一起。
此上下文对象表示 Camel 运行时系统。通常,在一个应用程序中只有一个 CamelContext 实例。
您在创建的示例应用程序中没有操作 CamelContext,因为 Main 组件为您管理了它。随着您的集成变得更加复杂,您最终将需要对其进行操作。典型的应用程序执行以下步骤:
-
创建上下文对象。 -
添加端点和可能的组件,我们将在"组件"部分讨论。 -
将路由添加到上下文对象以连接端点。 -
在上下文对象上调用start()
操作。此操作启动 Camel 内部线程,用于处理端点中的消息发送、接收和处理。 -
最终在上下文对象上调用stop()
操作。通过这样做,优雅地停止所有的端点和 Camel 内部线程。
|
如果您在应用程序中忽略调用 CamelContext.start()
,Camel 将不会处理消息,因为内部线程将不会被创建。
如果您在终止应用程序之前忽略调用 CamelContext.stop()
,它可能会以不一致的状态终止。如果您在 JUnit 测试中忽略调用 CamelContext.stop()
,它可能会失败,因为消息没有完全处理的机会。
|
组件
组件是 Apache Camel 的另一个基本构建块,用于将路由连接到各种外部系统和服务。Camel 提供了大量内置组件,可以连接到各种技术和协议,如 HTTP、JMS、文件等。如果内置组件不能满足您的需求,您还可以创建自定义组件。
通常,基于 Camel 的应用程序不需要直接与组件进行交互。然而,在某些情况下,操作组件可能有助于应用程序的性能、操作或可扩展性。如果您想了解更多信息,包括编写自己所需的重要细节,我们的文档中包含了对组件的深入概述。
信息和交流
Message
接口提供了对单个消息的抽象,例如请求、回复或异常消息。
Message
接口的公共 API 提供了获取器和设置器方法。您可以使用它们来访问消息的消息 ID、正文和各个头字段。
Exchange
接口提供了消息交换的抽象。消息交换是一个请求消息及其对应的回复或异常消息。在 Camel 中,请求、回复和异常消息分别称为 in、out 和 fault 消息。
|
处理器
处理器用于实现消息交换的消费者或实现消息转换器等其他用例。
在编写路由时,您可以使用处理器在交换机上执行更复杂的逻辑。例如:
public void process(Exchange exchange) {
final String body = exchange.getMessage().getBody(String.class);
System.out.println(“Updated body: “ + body.replace(“city”, “county”));
// ... more code here
}
public void configure() {
from(“file:src/data?noop=true”)
.process(this::process);
}
处理器的代码必须符合 Processor
接口。该接口代表处理消息的类。我们在下面展示该接口的签名:
package org.apache.camel;
public interface Processor {
void process(Exchange exchange) throws Exception;
}
|
一个应用级开发者可能还想使用一个执行一些业务逻辑的类来实现 Processor
接口。
|