在路由route的整个生命周期中,Exchange是相同的,但是Message消息可能发生变化,例如,如果Message从一种格式转换为另一种格式。我们在架构之前讨论了Camel的消息模型,因为我们希望您对Camel中的消息有一个扎实的理解。毕竟,Camel最重要的方面是 routing message路由消息。现在我们来准备好了解更多关于Camel及其架构的知识了。
Camel 架构
我们从高层次看向Camel的架构
从高层次看,Camel由
- routes
- processors
- components
组成,并且这些全都包含在CamelContext
中。
- Routing engine路由引擎使用routes路由规范、指示Message消息的路由位置。
- Routes路由可以使用Camel提供的DSL定义路由route。
- Processors处理器用于路由过程中转换和操作消息,并实现所有EIP,它们在DSL具有相应的名称。(例如split、marshal)
- Components组件是Camel中的扩展点,用于向其他系统添加连接性。(例如使用File组件,就能操作文件系统了)。为了将这些系统公开给Camel的其余部分,组件提供了一个endpoint端点接口。
Camel相关概念
CamelContext
CamelContext是一种容器,是Camel运行时系统。
CamelContext提供了对许多有用服务的访问,其中最引人注目的是
-
Components (组件)
-
Type converters(类型转换器)
-
Registry(注册中心)
-
Endpoints(端点)
-
Routes(路由)
-
Data formats(数据格式)
-
Languages(语言)
Service | Description |
---|---|
Components | 包含所使用的组件。Camel能够通过在类路径上自动发现或在OSGi容器中激活新bundle的方式动态加载组件。 |
Endpoints | 包含已使用的端点。 |
Routes | 包含以添加的路由。 |
Type converters | 包含已加载的类型转换器。Camel有一种机制,允许你手动或自动地从一种类型转换为另一种类型。 |
Data formats | 包含已加载的数据格式。 |
Registry | 包含允许你查找 Bean 的注册中心。 |
Languages | 包含加载的语言。Camel允许您使用多种语言来创建表达式。例如(XPath) |
Routing Engine
Camel的路由引擎在底层移动消息。这个引擎没有公开给开发人员,但是我们应该知道它在那里,它完成了所有繁重的工作,确保消息被正确路由。
Routes
路线是 Camel 的核心抽象。定义路由的最简单方法是作为处理器链。在消息传递应用进程中使用路由器的原因有很多。例如,通过将客户端与服务器分离,将生产者与用户分离,路由可以执行以下操作:
-
动态决定客户端将调用的服务器
-
提供一种灵活的方式来添加额外的处理
-
允许客户端和服务器独立开发
-
通过连接能够很好地完成一件事的不同系统来促进更好的设计实践
-
允许出于测试目的(使用模拟)将服务器的客户端存根
Camel中的每条route都有一个唯一的标识符。您可以使用该标识符来记录、调试、监控以及启动和停止路由。
Route路由具有且只有一个消息输入源。它们有效地绑定到输入端点endpoint。
也就是说,在一条路由上有多个输入会有一些语法上的问题。以下面的Route为例:
java
from("jms:queue:A", "jms:queue:B", "jms:queue:C").to("jms:queue:D");
以上语法是不支持的,一个Route有三个输入源。在Camel2.x中是合法的,但是底层还是会变成这样:
java
from("jms:queue:A").to("jms:queue:D");
from("jms:queue:B").to("jms:queue:D");
from("jms:queue:C").to("jms:queue:D");
Domain-specific language(DSL)
为了将processors处理器和endpoints端点连接在一起形成路由,Camel定义了DSL
下面就使用了Java DSL定义了一个Route
java
from("file:data/inbox")
.filter().xpath("/order[not(@test)]")
.to("jms:queue:order");
在一条Java语句中,定义了一条从file endpoint文件端点使用file文件的路由。Camel使用Filter EIP使用XPath predicate谓词来路由消息,以测试消息是否不是测试订单。如果消息通过了测试,Camel将其转发到JMS端点。过滤测试失败的消息将被跳过。
Camel提供多种DSL语言,因此我们可以通过使用XML DSL定义相同的路由,如下所示:
xml
<route>
<from uri="file:data/inbox"/>
<filter>
<xpath>/order[not(@test)]</xpath>
<to uri="jms:queue:order"/>
</filter>
</route>
YAML
yaml
- from:
uri: "file:data/inbox"
steps:
- filter:
xpath: "/order[not(@test)]"
steps:
- to: "jms:queue:order"
后面会详细介绍DSL
Processor
Processor是Camel的核心概念,它表示能够使用、创建或修改传入交换的节点。在路由过程中,交换从一个Processor流向另一个Processor。
因此,您可以将Route路由想象成一个图形,其中有专门的Processor作为节点,以及将一个Processor的输出连接到另一个Processor的输入的线路。Processor可以是EIP 的实现(split、marshal...)、特定组件的生产者producers 或 自己的自定义代码。下图显示了处理器之间的流程。
Route路由从填充初始交换的消费者(即 DSL 中的消费者)开始。
在每个处理器步骤中,上一步的输出(输出)消息是下一步的输入(输入)消息。
在许多情况下,处理器不会设置 out 消息,因此在这种情况下,会重用 in 消息。交换的交换模式决定了在路由结束时是否需要将回复发送回路由的调用方。如果交换模式 (MEP) 为 InOnly,则不会发回任何回复。如果是 InOut,Camel 将从上一步中获取 out 消息并返回它。
Component
Component组件是Camel中最为主要的扩展点,Camel提供了非常多的组件给我们使用。如果你还记得这张图的话。
从编程的角度来看,组件相当简单:它们与 URI 中使用的名称相关联,并充当端点的工厂。
例如,FileComponent 在 URI 中被 file 引用,它可以创建 FileEndpoint。
Endpoint
Endpoint端点是 Camel 的抽象概念,它是系统发送或接收信息的通道末端的模型。
我们通过例子来理解这个抽象概念。
在 Camel 中,你可以使用 URI(如file:data/inbox?delay=5000
)来配置端点,也可以用这种方式来引用端点。运行时,Camel 会根据 URI 符号查找端点。下图显示了其工作原理。
- Scheme表示哪个Camel组件处理该类型的端点,在上面这个例子,是使用了File组件。然后FileComponent像工厂一样工作,基于URI的剩余部分创建FileEndpoint。
- Context path则是告诉File组件的的起始目录是
data/inbox
- Options则是配置这个File组件以5秒的时间间隔轮询这个文件夹。
我们可以在官网的File组件中的Endpoint options找到这个选项的含义。
Endpoint端点充当工厂,用于创建能够向特定端点接收和发送消息的消费者和生产者。
Producer
Producer生产者是Camel抽象,它指的是能够向端点发送消息的实体。当消息发送到端点时,生产者处理获取与该特定端点兼容的消息数据的详细信息。
例如,FileProducer将消息体写入java.io.File。另一方面,JmsProducer会在将Camel消息发送到JMS目的地之前将其映射到javax.jms.Message。
这是 Camel 的一个重要特征,因为它隐藏了与特定传输交互的复杂性。您需要做的就是将消息路由到端点,然后由生产者完成繁重的工作。
Consumer
消费者是接收由外部系统产生的消息的服务,将它们封装在交换器中,并将它们发送给处理。消费者是在Camel中路由的交换的来源。要创建一个新的交换,消费者将使用包装被消费的有效负载的端点。然后使用处理器通过路由引擎在Camel中发起交换的路由。
Camel有两种消费者:
- EVENT DRIVEN CONSUMER 事件驱动的消费者。
- POLLING CONSUMER / SCHEDULED POLLING CONSUMER 轮询消费者/预定的轮询消费者)。
这些消费者之间的差异很重要,因为他们帮助解决不同的问题。
Event-driven consumer
这可能是我们最熟悉的消费者。
这类消费者主要与client-server体系结构和web服务相关联。在EIP世界中,它也被称为异步接收器。
事件驱动的使用者监听特定的消息传递通道,如TCP/IP端口、JMS队列、Twitter处理器、Amazon SQS队列、WebSocket等。然后等待客户端向它发送消息。当消息到达时,消费者将被唤醒并接受该消息进行处理。
Polling consumer
与事件驱动的消费者相比,轮询消费者主动去和从特定源(如 FTP 服务器)获取邮件。轮询消费者在 EIP 术语中也称为同步接收器,因为它不会轮询更多消息,直到它完成对当前消息的处理。
轮询消费者的一种常见类型是计划轮询消费者,它以计划的间隔进行轮询。File、FTP和Email组件都使用预定的轮询消费者。
举个例子:我们使用的File组件的消费者是一个Polling consumer,它会轮询的判断指定的文件夹中是否存在可以被消费的文件,而不是像Event-drven消费者一样,只要这个文件夹里面有文件可以消费就马上被消费,而是刚好轮到并且这个文件夹中存在文件可以消费才会触发消费,并且不会消费更多的文件,知道完成对当前消息的处理。
回顾第一个程序
java
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class FileCopierWithCamel {
public static void main(String args[]) throws Exception {
// create CamelContext
CamelContext context = new DefaultCamelContext();
// add our route to the CamelContext
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:C:/Users/kylin/Desktop/test?noop=true"). from("file:C:/Users/kylin/Desktop/test?noop=true");
}
});
// start the route and let it do its work
context.start();
Thread.sleep(10_000);
// stop the CamelContext
context.stop();
}
}
- 我们首先创建了CamelContext
- 然后使用RouteBuilder创建了一个Route路由,使用的方式是Java DSL(configure中的代码)。并且添加到CamelContext
- 并且通过URI可以看出我们使用了file组件,定义了文件路径,和相关参数noop。
- URI配置了两个Endpoint。其中消费者File Consumer是在
from(xxxx)
,File Producer生产者是在to(xxxx)
,都是由File组件创建出来的。(两个File Component 创建了 Endpoin,并分别创建了Consumer,Producer) - File Component -> Endpoint -> Consumer
from("file:C:/Users/kylin/Desktop/test?noop=true")
- File Component -> Endpoint -> Producer
from("file:C:/Users/kylin/Desktop/test?noop=true")
理解了Apache Camel的架构和相关概念后,我们对我们的第一个Camel程序又有了不同的理解~