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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章