Apache Camel源码研究之Intercept

Intercept作为一个极其强大的扩展机制,其理念几乎存在于所有知名框架中,诸如Spring,Mybatis,Tomcat等等都无一例外地提供了相应的支持,在保持自身框架本身整洁的同时,实现对各类业务场景的支持。而我们的Apache Camel也毫不意外地也提供了自己的Intercept实现,本文我们将尝试对Apache Camel的支持方式和实现逻辑进行一次探究,以期做到熟练运用。

1. 概述

Apache Camel中作为EIP实现者,诸如"当xxxx的时候,系统需要yyyy"的场景应该是属于常规需求了。Apache Camel提供了多种方式来完成对其的支持,本文将注意力集中到其中的一种实现方式 —— Intercept。

2. 源码解读

首先依然是本次的测试用例:

CamelTestUtil.defaultPrepareTest2(new RouteBuilder() {

	@Override
	public void configure() throws Exception {										
		intercept().process(new Processor() {
			@Override
			public void process(Exchange exchange) throws Exception {
				Console.error("intercept - " + exchange.getIn().getBody());
			}
		}).id("interceptProcess");
		
		// EmptyProcessor为一个空的Processor实现, 里面不作任何操作
		from("stream:in?promptMessage=Enter something:")//
				// 这里intercept输出 键入的内容
				.setBody(constant("1")).id("setBody-1")//
				// 这里intercept输出 上面的1
				.process(EmptyProcessor.me).id("EmptyProcessor1")//
				// 这里intercept输出 上面的1
				.setBody(constant("2")).id("setBody-2")//
				// 这里intercept输出 上面的2 
				.process(EmptyProcessor.me).id("EmptyProcessor2")//
				// 这里intercept输出 上面的2 
				.to("stream:err") // 这里输出红色的2
				// 这里输出 上面的2 
				.process(CamelLogRecordProcessor.me).id("logProcessor");

	}

});
}

本次的源码解读按照之前的博客格式,依然是分为两部分:

2.1 启动时

首先让我们来看看在初始化阶段,Apache Camel是如何将Intercept功能组装进Camel执行链条中的。

以上用例启动之后,有以下两个比较重要的堆栈信息:

堆栈一(准备intercept实现者InterceptDefinition):
堆栈一

  1. 以上截图自RouteDefinitionHelper工具类,笔者特意将注释部分进行了保留,从中我们可以得知Apache Camel通过将 InterceptDefinition实例作为output集合中的第一个,实现了在intercept优先于actual route进行处理。这样就可以实现拦截所有node的目标。
  2. 图中字段intercept字段指向的实际类型正是InterceptDefinition

堆栈二(装配Intercept功能):
在这里插入图片描述
以上截图中:

  1. output字段指向的是测试用例配置的intercept()后配置的匿名Processor接口实现类。
  2. interceptedTarget字段指向的则是本次Route定义中的node,笔者本次截图是在第一次命中断点时候,因此这个node就是setBody()
  3. 上图中断点命中的位置可以看到 —— 作为拦截逻辑的匿名Processor实现和Route定义节点setBody()被封装为了一个Pipeline实例(注意两者的先后顺序,这关系到之后的执行顺序)。
  4. 在本次测试用例中,以上截图中的断点我们将命中六次,这正好对应测试用例中定义的node数量。
  5. 跳转到以上堆栈图中的DefaultChannel.initChannel()中,我们就会发现intercept()的实现是依赖于接口InterceptStrategy提供的扩展功能的。这一点从InterceptDefinition类间接继承自ProcessorDefinition,而其对于createProcessor方法的实现中就可见端倪。
2.2 执行时

在控制台敲入任意字符,我们将得到如下堆栈:
在这里插入图片描述
结合之前的系列博文,加之上一小节的初始化逻辑解析,我们可以很容易地解读出以上堆栈中表述的逻辑。

输入任意字符,我们将得到以下输出结果(结合上面的测试用例中的注释一起理解):
在这里插入图片描述

3. 扩展

其它诸如intercept()后接when()来进行条件拦截,或者interceptFrom()interceptSendToEndpoint(),限于篇幅原因本次就不再详述了,读者感兴趣的可以自行阅读相关源码或者下方给出的官方链接。

4. 总结

  1. 对应intercept(),Apache Camel内部使用InterceptDefinition类来统筹整个配置组装初始化的工作。而具体的实现逻辑则依赖于接口InterceptStrategy提供的扩展功能。这一点可以从InterceptDefinition类间接继承自ProcessorDefinition,而其对于createProcessor方法的实现中就可见端倪。
  2. 对应intercept(),其执行时机位于匹配node执行之前。正如上面解析的,Apache Camel使用Pipeline来将intercept功能和用户自定义node组装在一起,确保每个node拦截逻辑的独立性。

5. Links

  1. Office Site - Intercept
  2. Apache Camel源码研究之InterceptStrategy
  3. Apache Camel源码研究之ProcessorDefinition
  4. 《Camel In Action》 P178, 288, P377
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章