Apache Camel是一個非常實用的規則引擎庫,能夠用來處理來自于不同源的事件和信息。你可以在使用不同的協議比如VM,HTTP,FTP,JMS甚至是文件系統中來傳遞消息,并且讓你的操作邏輯和傳遞邏輯保持分離,這能夠讓你更專注于消息的內容。
在這篇文章中,我將提供一個Java語言(非Groovy)的Apache Camel入門演示。
首先創建一個Maven項目的pom.xml。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<? xml version = "1.0" encoding = "UTF-8" ?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> < modelVersion >4.0.0</ modelVersion > < groupId >camel-spring-demo</ groupId > < artifactId >camel-spring-demo</ artifactId > < version >1.0-SNAPSHOT</ version > < packaging >jar</ packaging > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < camel.version >2.11.1</ camel.version > </ properties > < dependencies > < dependency > < groupId >org.apache.camel</ groupId > < artifactId >camel-core</ artifactId > < version >${camel.version}</ version > </ dependency > < dependency > < groupId >org.slf4j</ groupId > < artifactId >slf4j-simple</ artifactId > < version >1.7.5</ version > </ dependency > </ dependencies > </ project > |
在這里我們只用到了camel-core.jar包,實際上它提供了許多你可能用到的實用組件。出于日志記錄的目的,我使用了slf4j-simple來作為日志記錄的實現,從而我們可以從控制臺上看到輸出。
接下來我們只需要構造一個路由類。路由就好比是Camel中怎樣將消息從一端傳遞到另一端的一個指令定義。我們將會創建src/main/java/camelcoredemo/TimerRouteBuilder.java文件,每隔一秒向處理器發送一個消息,簡單打印出來。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package camelcoredemo; import org.slf4j.*; import org.apache.camel.*; import org.apache.camel.builder.*; public class TimerRouteBuilder extends RouteBuilder { static Logger LOG = LoggerFactory.getLogger(TimerRouteBuilder. class ); public void configure() { from( "timer://timer1?period=1000" ) .process( new Processor() { public void process(Exchange msg) { LOG.info( "Processing {}" , msg); } }); } } |
以上就是這個示例的全部所需,現在編譯運行。
1
2
|
bash > mvn compile bash > mvn exec :java -Dexec.mainClass=org.apache.camel.main.Main -Dexec.args= '-r camelcoredemo.TimerRouteBuilder' |
注意,這里我們并沒有編寫Java類的main入口,我們只是將RouteBuilder的類名當作參數簡單傳遞給 org.apache.camel.main.Main,然后它將自動加載路由。
控制CamelContext
當啟動Camel后,它會創建一個CamelContext對象,該對象擁有了很多關于如何運行Camel的信息,還包含我們所創建的Route的定義。現在如果你想通過CamelContext獲得更多的控制,那么你需要編寫自己的主類代碼。我在這舉個簡單的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
package camelcoredemo; import org.slf4j.*; import org.apache.camel.*; import org.apache.camel.impl.*; import org.apache.camel.builder.*; public class TimerMain { static Logger LOG = LoggerFactory.getLogger(TimerMain. class ); public static void main(String[] args) throws Exception { new TimerMain().run(); } void run() throws Exception { final CamelContext camelContext = new DefaultCamelContext(); camelContext.addRoutes(createRouteBuilder()); camelContext.setTracing( true ); camelContext.start(); Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { try { camelContext.stop(); } catch (Exception e) { throw new RuntimeException(e); } } }); waitForStop(); } RouteBuilder createRouteBuilder() { return new TimerRouteBuilder(); } void waitForStop() { while ( true ) { try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { break ; } } } } |
可以看到,我們在createRouteBuilder()方法中重用了已有的TimerRouteBuilder類。現在我們的主類對在什么時候創建、啟動、停止CamelContext有了完全的控制。context(camelContext)對象允許你全局性地控制如何配置Camel,而不是在Route級。它的JavaDoc鏈接給出了所有setter方法,你可以研究下它都可以做些什么。
注意到一點,我們也需要在我們的主類中提供少量設置代碼。首先我們需要處理優雅關閉的問題,所以我們增加了一個Java關閉回調函數去調用context的stop()方法。其次在context已經啟動后,我們需要增加一個線程阻塞。如果在啟動后你不阻塞你的主線程,那么它會在啟動后就簡單的退出了,那就沒啥用了。你會把Camel一直作為一個服務(就像一個服務器)運行,直至你按下CTRL+C鍵去終止該進程。
改善啟動CamelContext的主類
如果你不想像上面例子一樣過多的處理主類設置代碼,那么你可以簡單地繼承由camel-core提供的org.apache.camel.main.Main類作為代替。通過利用這個類,你不僅可以讓你的context自動設置,還可以獲得所有附加的命令行特性,比如控制進程運行多久,啟用追蹤,加載自定義route類等等。
重構了下上一個例子,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package camelcoredemo; import org.slf4j.*; import org.apache.camel.builder.*; import org.apache.camel.main.Main; public class TimerMain2 extends Main { static Logger LOG = LoggerFactory.getLogger(TimerMain2. class ); public static void main(String[] args) throws Exception { TimerMain2 main = new TimerMain2(); main.enableHangupSupport(); main.addRouteBuilder(createRouteBuilder()); main.run(args); } static RouteBuilder createRouteBuilder() { return new TimerRouteBuilder(); } } |
現在TimerMain2類的代碼比之前的更少了,你可以試試看,它應該和之前的功能一樣。
1
2
|
bash > mvn compile bash > mvn exec :java -Dexec.mainClass=camelcoredemo.TimerMain2 -Dexec.args= '-t' |
注意到我們給出-t選項后,會轉儲Route追蹤。使用-h會看到所有可用的選項。
用Camel的注冊機制添加bean
在之前的TimerRouteBuilder例子中,我們已經在代碼中創建了一個匿名Processor。現在如果你想將幾個不同的Processor放在一起,那么使用Camel的注冊機制添加bean的方式將能更好的減少代碼混亂。Camel允許你通過將processing當作bean注入到它的registry space,然后你只要把它們當作bean組件來進行調用。如下是我的重構代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package camelcoredemo; import org.slf4j.*; import org.apache.camel.*; import org.apache.camel.builder.*; import org.apache.camel.main.Main; public class TimerBeansMain extends Main { static Logger LOG = LoggerFactory.getLogger(TimerBeansMain. class ); public static void main(String[] args) throws Exception { TimerBeansMain main = new TimerBeansMain(); main.enableHangupSupport(); main.bind( "processByBean1" , new Bean1()); main.bind( "processAgainByBean2" , new Bean2()); main.addRouteBuilder(createRouteBuilder()); main.run(args); } static RouteBuilder createRouteBuilder() { return new RouteBuilder() { public void configure() { from( "timer://timer1?period=1000" ) .to( "bean:processByBean1" ) .to( "bean:processAgainByBean2" ); } }; } // Processor beans static class Bean1 implements Processor { public void process(Exchange msg) { LOG.info( "First process {}" , msg); } } static class Bean2 implements Processor { public void process(Exchange msg) { LOG.info( "Second process {}" , msg); } } } |
現在Route類更簡潔明了,同時處理代碼也被重構到了獨立的類中。當你需要編寫很復雜的Route來實現業務邏輯時,這種方式能夠幫助你更好的組織和測試你的代碼。它能夠讓你構建像”樂高“積木那樣可復用的POJO bean。Camel的registry space同樣可用于其他很多用途,比如你可以自定義許多具有附加功能的endpoint組件或者注冊一些信息,更或者替換線程池實現策略之內的事情。
上述Route示例是用所謂的Java DSL來構成的,它的可讀性較高,你可以用IDE提供的支持查看所有可用于Route的方法。
我希望這篇文章能夠幫助你跳過Camel的摸索階段。