Apache Camel提供了许多处理路由过程出现的Exception的机制,本文简单介绍一下其异常处理的方法.
1,默认的情况是在路由过程中没有处理的异常会被被抛出到路由的发起者,对发生异常的路由停止进行后续步骤的处理.
比如下面的路由在process(p1)出错,那么当前路由停止,文件不会到达"d:/temp/outbox",同时d:/temp/inbox里造成异常的那个文件仍然留在d:/temp/inbox文件夹中,由于Camel会轮询这个文件夹,所以下次轮询时,对这个文件处理的时候会继续异常.
from("file:d:/temp/inbox?delay=30000").process(p0).process(p1).to("file:d:/temp/outbox"); public class TProcessor0 implements Processor{ public void process(Exchange exchange) throws Exception { System.out.println("what if here has a transaction,later processing failed?"); } } public class TProcessor0 implements Processor{ public void process(Exchange exchange) throws Exception { String nullStr=null; nullStr.length(); } }
如果路由改成如下:因为异常是在process(p1)里发生,所以文件会会到达"d:/temp/outbox",但是d:/temp/inbox造成异常的文件仍然在d:/temp/inbox文件夹中,下次轮询时对这个文件处理的时候会继续异常.
from("file:d:/temp/inbox?delay=30000").to("file:d:/temp/outbox").process(p0).process(p1);
默认情况基本上就是已经做过的步骤没有rollback的操作,如果需要事务控制就更不行了.[会另外写一篇关于Camel如何做事务控制TransactionErrorHandler]
2,利用Camel提供的DeadLetterChannel将出错的消息路由到"死队列"里,然后停止当前的路由,其示例图如下:(图片来源于Camel in Action)
errorHandler(deadLetterChannel("file:d:/temp/error"));
from("file:d:/temp/inbox?delay=30000").process(p0).process(p1).to("file:d:/temp/outbox");
在process(p1)出错,处理会停止处理process(p1)之后的步骤,d:/temp/inbox里造成异常的文件会被放到d:/temp/error文件夹,d:/temp/inbox里的文件会被移走.
errorHandler(deadLetterChannel("file:d:/temp/error"));写在某一个routebuilder里的时候,是这个routebuilder所有路由的error handler.如果要为其中某一个路由指定error handler,示例如下:from("file:d:/temp/inbox?delay=30000").errorHandler(deadLetterChannel("file:d:/temp/error")).process(p0).process(p1).to("file:d:/temp/outbox");
3,利用Camel提供的onException功能,当有异常发生的时候,会根据不同的异常类型,跳到和onException里指定异常匹配的的步骤进行处理.
onException(NullPointerException.class).process(p2).handled(true).to("file:d:/temp/nullerror").end();
onException(TestException.class).process(p2).continued(true).to("file:d:/temp/TEerror").end();
from("file:d:/temp/inbox?delay=30000").process(p0).process(p1).to("file:d:/temp/outbox");//route xx
如上面在route builder里定义的话,当有NullPointerException发生的时候,会转到第一个onException,这时候会停止进行route xx的后续步骤处理(handled(true)设置的作用),将错误消息保存到:d:/temp/nullerror.当有TestException发生的时候,会转到第二个onException,这时候会将错误消息保存到:d:/temp/TEerror,忽略异常继续routexx的后续步骤(continued(true设置的作用).
Camel还支持类似如java try catch的语法,如下:TestException由process(p2)处理.
from("file:d:/temp/inbox?delay=30000").doTry().process(p0).process(p1).to("file:d:/temp/outbox")
.doCatch(TestException.class).process(p2)
.doCatch(NullPointerException.class).process(p2).end();
Camel的onException还可以和onWhen,onRedeliver,retryWhile结合使用.
onException(XXXException.class)
.onWhen(bean(XXX.class, "isIllegalData"))
.handled(true)
.to("file:/acme/files/illegal");
XXXException为异常的类型的类,XXX.class有一个isIllegalData方法返回true或者false,对异常进行更细致的区别处理.
errorHandler(defaultErrorHandler()
.maximumRedeliveries(3)
.onRedeliver(new MyOnRedeliveryProcessor());
onException(IOException.class)
.maximumRedeliveries(5)
.onRedeliver(new MyOtherOnRedeliveryProcessor());
在重新处理之前对exchange里的内容做一些改动的时候用onRedeliver.
public class MyRetryRuleset {
public boolean shouldRetry(@Header(Exchange.REDELIVERY_COUNTER) Integer counter,Exception causedBy) {
...
}
onException(IOException.class).retryWhile(bean(MyRetryRuletset.class));
在异常发生后捕捉到异常的点循环重试,直到MyRetryRuletset的shouldRetry方法返回false为止.