规则引擎 Apache camel (学习三)
重述下:Exchange要素帮助开发人员在控制端点到处理器、处理器到处理器的路由过程中完成消息的统一描述
1.Exchange中的基本属性
ExchangeID:
一个Exchange贯穿着整个编排的路由规则,ExchangeID就是它的唯一编号信息,
同一个路由规则的不同实例(对路由规则分别独立的两次执行),ExchangeID不相同。
fromEndpoint:
表示exchange实例初始来源的Endpoint控制端点(类的实例),一般来说就是开发人员设置路由时由“from”关键字所表达的Endpoint。
比如:from关键字填写的URI信息是“ jetty: http://0.0.0.0:8282/doHelloWorld ”,
而实现Jetty协议头支持的org.apache.camel.Endpoint接口实现类是org.apache.camel.component.jetty.JettyHttpEndpoint。
Exchange对象中的fromEndpoint属性就是JettyHttpEndpoint类的一个实例化对象。
properties:
Exchange对象贯穿整个路由执行过程中的控制端点、处理器甚至还有表达式、路由条件判断。
为了让这些元素能够共享一些开发人员自定义的参数配置信息,Exchange以K-V结构提供了这样的参数配置信息存储方式。
在org.apache.camel.impl.DefaultExchange类中,对应properties的实现代码如下所示:
......
public Map<String, Object> getProperties() {
if (properties == null) {
properties = new ConcurrentHashMap<String, Object>();
}
return properties;
}
......
Pattern:
介绍:Exchange中的pattern属性非常重要,它的全称是:ExchangePattern(交换器工作模式)。
其实现是一个枚举类型:org.apache.camel.ExchangePattern。
可以使用的值包括:InOnly, RobustInOnly, InOut, InOptionalOut, OutOnly, RobustOutOnly, OutIn, OutOptionalIn。
从Camel官方已公布的文档来看,这个属性描述了Exchange中消息的传播方式。
例子:例如 Event Message类型的消息,其ExchangePattern默认设置为InOnly。
Request/Reply Message类型的消息,其ExchangePattern设置为InOut。
但是笔者通过代码排查,发现并不是ExchangePattern都被Camel-Core核心实现部分所使用
(并不能说明没有被诸如 Camel-CXF这些pluin所使用),而且Camel的官方文档对于它们的介绍
也只有寥寥数笔(http://camel.apache.org/exchange-pattern.html)。
例如RobustOutOnly、OutOptionalIn、OutOnly这些枚举值就没有在Camel-Core实现部分发现引用。
Exception:
如果在处理器Processor的处理过程中,开发人员需要抛出异常并终止整个消息路由的执行过程,
可以通过设置Exchange中的exception属性来实现。
2.Exchange中的Message(这里我理解为Exchange是共有的,方便控制点,处理器之间的信息共享)
定义:Exchange中还有两个重要属性inMessage和outMessage。
这两个属性分别代表Exchange在某个处理元素(处理器、表达式等)上的输入消息和输出消息。
描述:
当控制端点和处理器、处理器和处理器间的Message在Exchange中传递时
(虽然ExchangePattern枚举中存在isInCapable()、isInCapable()这样的判断方法,但是通过代码排查,
笔者并没有发现在camel-core中有关于这些方法的任何使用),
Exchange会自动将上一个元素的输出值作为作为这个元素的输入值进行使用。
但是如果在上一个处理器中,开发人员没有在Exchange中设置任何out message内容(即Excahnge中out属性为null),
那么上一个处理器中的in message内容将作为这个处理器的in message内容。
例子:这里需要注意一个问题,在DefaultExchange类中关于getOut()方法的实现,有这样的代码片段:
......
public Message getOut() {
// lazy create
if (out == null) {
out = (in != null && in instanceof MessageSupport)? ((MessageSupport)in).newInstance() : new DefaultMessage();
configureMessage(out);
}
return out;
}
......
所以,在处理器中对out message属性的赋值,并不需要开发人员明确的“new”一个Message对象。
只需要调用getOut()方法,就可以完成out message属性赋值。以下路由代码片段在fromEndpoint后,
连续进入两个Processor处理器,且Exchange的ExchangePattern为InOut。我们来观察从第一个处理处理完后,
到第二个处理收到消息时Exchange对象中的各个属性产生的变化:
......
from("jetty:http://0.0.0.0:8282/doHelloWorld")
.process(new HttpProcessor())
.process(new OtherProcessor())
......
上图显示了当前内存区域中,Exchange对象的id为452,fromEndpoint属性是一个JettyHttpEndpoint的实例,对象id为479。
注意两个重要的inMessage和outMessage,它们分别是HttpMessage的实例(对象id467)和DefaultMessage的实例(对象id476),
这里说明一下无论是HttpMessage还是DefaultMessage,它们都是org.apache.camel.Message接口的实现。
outMessage中的body部分存储了一个字符串信息,我们随后验证一下信息在下一个OtherProcessor处理器中的记录方式。
可以看到HttpProcessor处理器中outMessage的Message对象作为了这个OtherProcessor处理器的inMessage属性,对象的id编号都是476,
说明他们使用的内存区域都是相同的,是同一个对象。Excahnge对象的其它信息也从HttpProcessor处理器原封不动的传递到了OtherProcessor处理器。
2.每一个Message(无论是inMessage还是outMessage)对象主要包括四个属性:MessageID、Header、Body和Attachment。
MessageID:在系统开发阶段,提供给开发人员使用的标示消息对象唯一性的属性,这个属性可以没有值。
Header:
介绍:消息结构中的“头部”信息,在这个属性中的信息采用K-V的方式进行存储,
并可以随着Message对象的传递将信息带到下一个参与路由的元素中。
例子:主要注意的是在org.apache.camel.impl.DefaultMessage中对headers属性的实现是一个名叫org.apache.camel.util.CaseInsensitiveMap的类。
看这个类的名字就知道:headers属性的特点是忽略大小写。也就是说:
......
outMessage.setHeader("testHeader", "headerValue");
outMessage.setHeader("TESTHEADER", "headerValue");
outMessage.setHeader("testheader", "HEADERVALUE");
......
总结:以上代码片段设置后,Message中的Headers属性中只有一个K-V键值对信息,且以最后一次设置的testheader为准。
Body:
Message的业务消息内容存放在这里
Attachment:
Message中使用attachment属性存储各种文件内容信息,以便这些文件内容在Camel路由的各个元素间进行流转。
attachment同样使用K-V键值对形式进行文件内容的存储。但不同的是,这里的V是一个javax.activation.DataHandler类型的对象。