1. Camel中的相关概念
1.1 ROUTING ENGINE(路由引擎)
Camel的路由引擎是消息移动的实际执行者,但并未暴露给开发者;不过作为开发者,我们应该意识到它的存在;并且它做了所有繁重的消息移动工作并保证了正确的路由。
1.2 ROUTES(路由)
路由是Camel的核心抽象概念,最简单的定义路由的方式是通过一个processors链来实现;在消息应用中使用路由有很多种原因,解耦的客户端和服务器端,生产者和消费者。
Camel中的每个路由都有一个惟一标识,用于日志记录、调试、跟踪,以及启动和停止路由等操作。路由也有一个输入消息源,所以每个路由有效地绑定到了输入的Endpoint。
路由定义使用领域标记语言(DSL)。
1.3 DOMAIN-SPECIFIC LANGUAGE (DSL 领域标记语言)
Camel中通过DSL,将processors 和 endpoints 连接在一起构成路由。
在Camel中,DSL意味着一个流畅的Java API,它包含以EIP术语命名的方法。
下面有一个简单的java代码块,其定义了一个路由实现如下功能:从文件终端消费文件,然后将消息路由到过滤器EIP,该过滤器EIP将使用XPath断言判断消息是否是测试订单,若消息是测试订单,则把消息路由发送到JMS终端,所不是则直接丢弃。
from("file:data/inbox")
.filter().xpath("/order[not(@test)]")
.to("jms:queue:order")
Camel提供多种DSL语言支持,所以你可以通过下面Spring Xml格式定义跟上面一样语义的路由实现:
<route>
<from uri="file:data/inbox"/>
<filter>
<xpath>/order[not(@test)]</xpath>
<to uri="jms:queue:order"/>
</filter>
</route>
1.4 PROCESSOR(处理器)
processor处理器是Camel的核心概念,它能够使用、创建和修改传入的Exchange;在路由过程中,Exchange从一个processor流转到另一个processor。
许多processor都是EIP的实现,但我们可以轻松实现任何一个,自定义自己的处理器并将其插入到我们需要的router路由中。
1.5 COMPONENT(组件)
Components 组件是Camel中的主要扩展点;到目前为止,在Camel生态系统中有超过80个组件,功能范围从数据传输到DSL、数据格式处理等。
我们也可以为Camel创建我们自定义的组件。
从编程的角度来看,组件相当简单:它们与URI中使用的名称关联,并充当Endpoint终端工厂。例如FileComponent是URI中引用的文件,它创建FileEndpoints。
在Camel中,Endpoint终端可能是一个更为基本的概念。
1.6 ENDPOINT(终端)
Endpoint终端是Camel中的一个抽象概念,他表示可以通过channel发送或接收消息的一个端点。
Endpoint端点的扮演着一个中立的允许进行系统集成的接口:
在Camel中使用uri配置或引用Endpoint,如:
file:data/inbox?delay=5000
在运行时,Camel将根据URI中的标记符号查找对应的Endpoint,下图展示了具体工作细节:
- Scheme:标识哪个Camel组件处理这种类型的Endpoint,这里使用的是file标识FileComponent;之后FileComponent作为一个工厂,基于URI的其余部分创建对应的FileEndpoint
- Context path:上下文路径data/inbox告诉FileComponent开始位置是data/inbox;
- Options:选项delay=5000 表示以5秒为间隔轮询文件
Endpoint的含义还有很多,下图展示了Endpoint如何与exchange、producer和consumer一起协作:
简而言之,Endpoint充当创建producer(发送消息)和consumer(接收消息)的工厂。
1.7 PRODUCER(生产者)
producer是Camel中的一个抽象概念,他表示可以创建和发送消息到一个Endpoint的主体。
当消息需要发送到Endpoint时,producer将创建一个Endpoint并用具体的消息数据填充它。例如,FileProducer将把消息body写入文件;一个JmsProducer,将把Camel消息在发送到JMS目的地之前映射为javax.js.message。
这在Camel中是一个重要的特性,因为它隐藏了与特定对象交互的复杂性。我们所需要做的就是把一个message路由到一个Endpoint,然后由producer来做这些繁杂的工作。
1.8 CONSUMER(消费者)
consumer是接收producer产生的message的服务,并将消息包装为exchange,然后还可将消息交给processor进行处理。
consumer要创建新的exchange,consumer将使用该exchange包装message。然后使用processor来启动exchange路由,并在Camel路由引擎中流转。
在Camel中有两种consumer:
- event-driven consumers:事件驱动的消费者
- polling consumers:轮询
1.8.1 EVENT-DRIVEN CONSUMER (事件驱动的消费者)
最熟悉的consumer可能是就是event-driven consumers事件驱动消费者,如下图所示:
event-driven consumers事件驱动消费者大多是关联client-server架构和web服务,在EIP中被称为异步接收者。
event-driven consumers事件驱动消费者通过对特定的消息传递通道进行监听,比如TCP/IP端口或JMS队列,等待client向其发送消息。当一个
消息到达时,consumer苏醒并接受消息进行处理。
1.8.2 POLLING CONSUMER (轮询消费者)
polling consumers 轮询消费者,如下图所示:
与event-driven consumers事件驱动消费者相反,polling consumers 轮询消费者主动轮询访问并从特定的消息源(例如FTP服务器)获取消息。
polling consumers 轮询消费者在EIP中也被称为同步接收器,因为它在完成当前消息的处理之前,不会轮询获取更多的消息。
常见的是定时轮询消费者,它通过预定的时间间隔进行轮询。文件、FTP和电子邮件传输都使用定时轮询消费者。
2. 简单demo
2.1 需求
使用Apache Camel,从一个文件夹(data/发件箱)读取文件,并将读取的文件结果写入另一个文件(data/发件箱)
2.2 demo代码
public class FileCopierWithCamel {
public static void main(String args[]) throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:data/inbox?noop=true")
.to("file:data/outbox");
}
});
context.start();
Thread.sleep(10000);
context.stop();
}
}
上面例子中,首先创建一个CamelContext,它是Camel运行时上下文。然后使用RouteBuilder和Java DSL 添加路由逻辑
通过DSL,可以简洁明了地让Camel实例化components组件、endpoint终端、consumers消费者、producer生产者等等。
而作为使用者的我们,仅仅需要关注的是为集成项目而定义的router路由。
但实际上,Camel会实际访问FileComponent,并使用它作为工厂来创建endpoint端点及producer生产者,同样的FileComponent也用于创建consumer消费者。
3. 企业集成相关概念
上面介绍了Apache Camel中的相关核心概念,其中大部分来源于Gregor Hohpe 和 Bobby Woolf 的优秀著作中企业集成模式](http://www.eaipatterns.com/toc.html),且Camel 支持其中的大部分。
这里对其中的重点概念做如下列举介绍:
3.1 消息系统(Message Endpoint)
类型 | 说明 | 解释 |
---|---|---|
Message Channel 留言频道 | 一个应用程序如何使用消息传递与另一个应用程序通信? | |
Message 信息 | 一个消息通道连接的两个应用程序如何交换一条信息? | |
Pipes and Filters 管道和过滤器 | 我们如何在保持独立性和灵活性的同时对消息进行复杂的处理? | |
Message Router 消息路由器 | 如何解耦各个处理步骤,以便根据一组条件将消息传递到不同的过滤器? | |
Message Translator 消息翻译器 | 使用不同数据格式的系统如何使用消息传递相互通信? | |
Message Endpoint 消息终端 | 应用程序如何连接到消息通道以发送和接收消息? |
3.2 消息渠道(MESSAGING CHANNELS)
分类 | 说明 | 解释 |
---|---|---|
Point to Point Channel 点对点通道 | 发送者如何确定只有一位接收者会收到内容或执行? | |
Publish Subscribe Channel 发布订阅频道 | 发送方如何向所有感兴趣的接收方广播事件? | |
Dead Letter Channel 死信频道 | 消息传递系统将如何处理它无法传递的消息? | |
Guaranteed Delivery 保证交付 | 即使消息传递系统出现故障,发件人如何确保消息会被传递? | |
Channel Adapter 通道适配器 | 如何将应用程序连接到消息传递系统,以便它可以发送和接收消息? | |
Messaging Bridge 消息桥 | 如何连接多个消息传递系统,以便在一个消息系统上可用的消息也可在其他消息系统上使用? | |
Message Bus 消息总线 | 什么样的架构可以让不同的应用程序协同工作,但以解耦的方式使应用程序可以轻松添加或删除而不会影响其他应用程序? | |
Change Data Capture 变更数据捕获 | 通过捕获对数据库所做的更改并将这些更改应用到另一个系统来实现数据同步。 |
3.3 消息构造(MESSAGE CONSTRUCTION)
分类 | 说明 | 解释 |
---|---|---|
Event Message 事件消息 | 如何使用消息传递将事件从一个应用程序传输到另一个应用程序? | |
Request Reply 请求回复 | 当应用程序发送消息时,它如何从接收者那里得到响应? | |
Return Address 退货地址 | 回复者如何知道将回复发送到哪里? | |
Correlation Identifier 相关标识符 | 收到回复的请求者如何知道这是针对哪个请求的回复? | |
Message Expiration 消息过期 | 发件人如何指示何时应将消息视为过时且不应处理? |
3.4 消息路由(MESSAGE ROUTING)
分类 | 说明 | 解释 |
---|---|---|
Content Based Router 基于内容的路由器 | 我们如何处理单个逻辑功能(例如库存检查)的实现分布在多个物理系统中的情况? | |
Message Filter 消息过滤器 | 组件如何避免接收无趣的消息? | |
Dynamic Router 动态路由器 | 如何在保持其效率的同时避免路由器对所有可能目的地的依赖? | |
Recipient List 收件人列表 | 我们如何将消息路由到(静态或动态)指定收件人列表? | |
Splitter 分路器 | 如果一条消息包含多个元素,每个元素可能必须以不同的方式进行处理,我们如何处理它? | |
Aggregator 聚合器 | 我们如何组合单独但相关的消息的结果,以便将它们作为一个整体进行处理? | |
Resequencer 重测序器 | 我们如何才能将相关但无序的消息流恢复到正确的顺序? | |
Composed Message Processor 组合消息处理器 | 在处理由多个元素组成的消息时,您如何维护整体消息流,每个元素可能需要不同的处理? | |
Scatter-Gather 分散-聚集 | 当一条消息需要发送给多个收件人时,您如何维护整个消息流,每个收件人都可能发送回复? | |
Routing Slip 路线单 | 当步骤序列在设计时未知并且可能因每条消息而异时,我们如何通过一系列处理步骤连续路由消息? | |
Process Manager 流程管理 | 当所需的步骤在设计时可能未知并且可能不是顺序的时,我们如何通过多个处理步骤路由消息? | |
Message Broker 消息代理 | 如何将消息的目的地与发送方分离并保持对消息流的中央控制? | |
Throttler 限流 | 我如何限制消息以确保特定端点不会过载,或者我们不会超过与某些外部服务达成的 SLA? | |
Sampling 采样 | 如何在给定时间内从众多消息中抽取一条消息以避免下游路由过载? | |
Kamelet 模板 | 我如何调用 Kamelets(路由模板)。 | |
Delayer 延迟器 | 如何延迟发送消息? | |
Load Balancer 负载均衡器 | 如何在多个端点之间平衡负载? | |
Circuit Breaker 断路器 | 如果服务中断,如何停止调用外部服务? | |
Service Call 服务调用 | 如何在分布式系统中调用远程服务,该服务是从某种服务注册表中查找的? | |
Saga 条件选择 | 如何在 Camel 路线中定义一系列相关操作,要么成功完成(全部)要么不执行/补偿? | |
Multicast 组播 | 如何同时将消息路由到多个端点? | |
Loop 循环 | 如何在循环中重复处理消息? |
3.5 消息转换(MESSAGE TRANSFORMATION)
分类 | 说明 | 解析 |
---|---|---|
Content Enricher 内容丰富 | 如果消息发起者没有可用的所有必需数据项,我们如何与另一个系统通信? | |
Content Filter 内容过滤器 | 当您只对少数数据项感兴趣时,如何简化处理大消息的过程? | |
Claim Check 索赔检查 | 我们如何在不牺牲信息内容的情况下减少跨系统发送的消息的数据量? | |
Normalizer 归一化器 | 您如何处理语义相同但以不同格式到达的消息? | |
Sort 排序 | 如何对邮件正文进行排序? | |
Script 脚本 | 如何执行可能不会更改消息的脚本? | |
Validate 校验 | 如何验证消息? |
3.6 消息端点(MESSAGING ENDPOINTS)
分类 | 说明 | 解释 |
---|---|---|
Messaging Mapper 消息映射器 | 您如何在域对象和消息传递基础设施之间移动数据,同时保持两者相互独立? | |
Event Driven Consumer 事件驱动的消费者 | 应用程序如何在消息可用时自动使用它们? | |
Polling Consumer 轮询消费者 | 当应用程序准备好时,应用程序如何消费消息? | |
Competing Consumers 竞争消费者 | 消息客户端如何同时处理多条消息? | |
Message Dispatcher 消息分发器 | 单个通道上的多个消费者如何协调他们的消息处理? | |
Selective Consumer 选择性消费者 | 消息消费者如何选择它希望接收的消息? | |
Durable Subscriber 持久订阅者 | 订阅者如何避免在不收听消息时丢失消息? | |
Idempotent Consumer 幂等消费者 | 消息接收者如何处理重复消息? | |
Transactional Client 交易客户 | 客户端如何通过消息传递系统控制其事务? | |
Messaging Gateway 消息网关 | 您如何封装从应用程序的其余部分对消息传递系统的访问? | |
Service Activator 服务激活器 | 应用程序如何设计服务以通过各种消息传递技术和非消息传递技术调用? |
3.7 系统管理(MESSAGING ENDPOINTS)
分类 | 说明 | 解析 |
---|---|---|
ControlBus 控制总线 | 我们如何有效地管理分布在多个平台和广泛地理区域的消息传递系统? | |
Detour 消息绕行 | 您如何通过中间步骤路由消息以执行验证、测试或调试功能? | |
Wire Tap 消息监听 | 您如何检查在点对点通道上传输的消息? | |
Message History 消息历史 | 在松耦合系统中,我们如何有效地分析和调试消息流? | |
Log 日志 | 如何记录处理消息? | |
Step 步骤 | 将一组 EIP 组合成一个复合逻辑单元,用于度量和监控。 |
文献:《Camel In Action》 Meeting Camel