Apache Camel简介
1.概述
在本文中,我们将介绍 Camel 并探讨其核心概念之一——消息路由。
我们将从介绍这些基本概念和术语开始,然后介绍定义路由的两个主要选项——Java DSL 和 Spring DSL。
我们还将通过一个示例来演示这些——通过定义一个路径,该路径使用一个文件夹中的文件并将它们移动到另一个文件夹,同时为每个文件名添加时间戳。
2. 关于 Apache Camel
Apache Camel 是一个开源集成框架,旨在简化集成系统。
它允许最终用户使用相同的 API 集成各种系统,提供对多种协议和数据类型的支持,同时具有可扩展性并允许引入自定义协议。
3. Maven依赖
为了使用 Camel,我们需要先添加 Maven 依赖:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.18.0</version>
</dependency>
可以在此处 找到最新版本的 Camel 工件。
3. 领域特定语言
路由和路由引擎是 Camel 的核心部分。路由包含不同系统之间集成的流程和逻辑。
为了更轻松、更简洁地定义路由,Camel 为 Java 或 Groovy 等编程语言提供了几种不同的领域特定语言 (DSL)。另一方面,它还提供了使用 Spring DSL 在 XML 中定义路由。
使用 Java DSL 或 Spring DSL 主要是用户偏好,因为大多数功能都可用。
Java DSL 提供了更多 Spring DSL 不支持的特性。然而,Spring DSL 有时更有益,因为无需重新编译代码即可更改 XML。
4. 术语和架构
现在让我们讨论基本的 Camel 术语和架构。
首先,我们将在这里看一下 Camel 的核心概念:
- **Message **包含正在传输到路由的数据。每条消息都有一个唯一的标识符,它由正文、标题和附件构成
- **Exchange **是消息的容器,它是在消费者在路由过程中收到消息时创建的。Exchange 允许系统之间进行不同类型的交互——它可以定义单向消息或请求-响应消息
- **Endpoint **是系统可以接收或发送消息的通道。它可以引用 Web 服务 URI、队列 URI、文件、电子邮件地址等
- **Component **充当端点工厂。简而言之,组件使用相同的方法和语法为不同的技术提供接口。Camel 已经在其 DSL 中为几乎所有可能的技术支持许多组件 ,但它也提供了编写自定义组件的能力
- Processor是一个简单的 Java 接口,用于向路由添加自定义集成逻辑。它包含一个单一的*process *方法,用于在消费者收到的消息上执行自定义业务逻辑
在高层次上,Camel 的架构很简单。CamelContext代表 Camel 运行时系统,它连接不同的概念,例如路由、组件或端点。 在此之下,处理器处理端点之间的路由和转换,而端点则集成不同的系统。
5. 定义路线
可以使用 Java DSL 或 Spring DSL 定义路由。
我们将通过定义一个路由来说明这两种样式,该路由使用一个文件夹中的文件并将它们移动到另一个文件夹,同时为每个文件名添加时间戳。
5.1.使用 Java DSL 进行路由
要使用 Java DSL 定义路由,我们首先需要创建一个DefaultCamelContext实例。之后,我们需要扩展RouteBuilder类并实现包含路由流的*configure *方法:
private static final long DURATION_MILIS = 10000;
private static final String SOURCE_FOLDER = "src/test/source-folder";
private static final String DESTINATION_FOLDER
= "src/test/destination-folder";
@Test
public void moveFolderContentJavaDSLTest() throws Exception {
CamelContext camelContext = new DefaultCamelContext();
camelContext.addRoutes(new RouteBuilder() {
@Override
public void configure() throws Exception {
from("file://" + SOURCE_FOLDER + "?delete=true").process(
new FileProcessor()).to("file://" + DESTINATION_FOLDER);
}
});
camelContext.start();
Thread.sleep(DURATION_MILIS);
camelContext.stop();
}
configure方法可以这样读取:从源文件夹读取文件,使用 FileProcessor 处理它们并将结果发送到目标文件夹。设置delete=true表示文件处理成功后将从源文件夹中删除。
为了启动 Camel,我们需要在CamelContext上调用start方法。调用Thread.sleep是为了让 Camel 有时间将文件从一个文件夹移动到另一个文件夹。
FileProcessor实现Processor接口并包含单个*process *方法,其中包含用于修改文件名的逻辑:
public class FileProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
String originalFileName = (String) exchange.getIn().getHeader(
Exchange.FILE_NAME, String.class);
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH-mm-ss");
String changedFileName = dateFormat.format(date) + originalFileName;
exchange.getIn().setHeader(Exchange.FILE_NAME, changedFileName);
}
}
为了检索文件名,我们必须从交换中检索传入消息并访问其标题。与此类似,要修改文件名,我们必须更新消息头。
5.2. 使用 Spring DSL 进行路由
在使用 Spring DSL 定义路由时,我们使用 XML 文件来设置路由和处理器。这允许我们使用 Spring 无需代码即可配置路由,并最终为我们提供了完全控制反转的好处。
这已经在现有文章 中介绍过,因此我们将重点关注使用 Spring DSL 和 Java DSL,这通常是定义路由的首选方式。
在这种安排中,CamelContext 是在 Spring XML 文件中使用 Camel 的自定义 XML 语法定义的,但没有像使用 XML 的“纯”Spring DSL 那样的路由定义:
<bean id="fileRouter" class="com.blogdemo.camel.file.FileRouter" />
<bean id="fileProcessor"
class="com.blogdemo.camel.file.FileProcessor" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="fileRouter" />
</camelContext>
通过这种方式,我们告诉 Camel 使用FileRouter类,该类包含我们在 Java DSL 中的路由定义:
public class FileRouter extends RouteBuilder {
private static final String SOURCE_FOLDER =
"src/test/source-folder";
private static final String DESTINATION_FOLDER =
"src/test/destination-folder";
@Override
public void configure() throws Exception {
from("file://" + SOURCE_FOLDER + "?delete=true").process(
new FileProcessor()).to("file://" + DESTINATION_FOLDER);
}
}
为了测试这一点,我们必须创建一个ClassPathXmlApplicationContext实例,它将在 Spring 中加载我们的CamelContext:
@Test
public void moveFolderContentSpringDSLTest() throws InterruptedException {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("camel-context.xml");
Thread.sleep(DURATION_MILIS);
applicationContext.close();
}
通过使用这种方法,我们获得了 Spring 提供的额外灵活性和好处,以及使用 Java DSL 实现 Java 语言的所有可能性。