Camel支持复杂的异步处理机制。
异步Processor实现AsyncProcessor接口,该接口派生自syncProcessor接口。
使用异步处理机制的好处是:
1.执行中的路由,如果都是由异步processor组成的话,不需要线程等待。
2.执行中的路由,可以分解成SEDA处理阶段,不同的线程池处理不同的阶段,这意味着路由可以并行执行。
?何时使用异步处理
我们的本意是建议你使用同步processor,除非你觉得系统的性能可扩展性是最重要的因素。
接口描述:
public interface AsyncProcessor extends Processor { boolean process(Exchange exchange, AsyncCallback callback); }
说明:
1.callback对象必须被提供,该对象将在process方法执行完后被回调。
2.在执行过程中,不能抛出错误,而是应该把错误存在exchange的错误属性里。
3.必须知道是同步执行完Process方法还是异步,如果是同步执行完,返回true,否则返回false。
4.当Processor执行完process方法后,他必然要调用callback.done(boolean sync)方法,该参数必须与process方法的返回参数值一致。
?如何进行异步处理编程
所有的processor,即使是没有实现异步接口的同步processor,都可以强制转换成实现异步接口。通常的场景是:消息的消费者生成一个processor,通过下面代码转换成异步处理方式:
Processor processor = ... AsyncProcessor asyncProcessor = AsyncProcessorTypeConverter.convert(processor);
对于一个路由来说,要达到全异步,并获得低线程使用率的益处,那么这个路由必须开始于一个异步处理的消息消费者的processor。如果调用了同步处理的方法,消费者线程将被阻塞,在他处理完消息后才能够结束阻塞。
值得注意的是,你仅仅是调用了异步API,并不代表整个处理进程都异步了。这里仅仅是意味着,处理器线程没有和调用者线程绑定。如果处理异步发生,实际上依赖于router的配置(不解)。
final Exchange exchange = ... AsyncProcessor asyncProcessor = ... asyncProcessor.process(exchange, new AsyncCallback() { public void done(boolean sync) { if (exchange.isFailed()) { ... // do failure processing.. perhaps rollback etc. } else { ... // processing completed successfully, finish up // perhaps commit etc. } } });
上面的代码告诉你,如何来写一个process方法。
?异步处理的场景
我们理解了异步的接口定义后,下面来看看在调用processor时,如何使用异步处理。
jetty组件消费者支持使用延续性来处理异步情况:该组件获得一个http request后,将它传递给一个router,由该路由进行异步处理。如果处理真的是异步的话,那么请求被暂留而consumer的线程被释放。一旦router完成了处理,jetty组件使用AsyncCallback,告诉jetty放行request,response生成,将结果返回给请求端。
注意:jetty的延续性特性,是依赖在进程真的是异步的前提下的。这就是为什么前面说过的,AsyncCallback.process方法必须准确反映请求是否真的是异步处理的。
jhc组件的producer允许你生成http Request并且实现AsyncProcessor接口,一个路由可以使用jetty的异步consumer和jhc的异步producer,这样就是一个完整的异步路由了。如果我们看一下处理路由的序列图,就可以看出它有很多好处了。
from("jetty:http://localhost:8080/service").to("jhc:http://localhost/service-impl");
上面的序列图,简化了router的处理流程,它假设processor实现了异步回调接口。但是它也充分说明了处理流程:两个独立的线程如何如何来处理源请求。
第一个线程,调用是同步的,直到进程触发了jhc producer,将request发出。发出后,该线程报告数据交换进程异步结束(使用NIO完成获取返回response的工作)。
一旦jhc组件接收到response,他将使用AsyncCallback.done()方法来通知调用者,回调通知送达jetty consumer组件后,该组件放行request并反馈response。
?同步异步混合场景
将同步和异步组件/处理器混合使用,是完全有可能和合理的。pipeline是处理路由的脊梁,它将不同的组件粘合在一起。它是作为异步处理器实现的,支持同步异步处理器交错。
例子如下:有两个自定义处理器,MyValidator 和MyTransformation他们都是同步处理器,我们打算从data/in目录装在文件并使用MyValidator方法去验证他们,将他们转换成java对象插入数据库中。由于transformation进程要花一些时间,所以分配20个线程并行处理,该解决方案还用到了线程processor,该线程processor是异步处理器,他生成子处理,子处理是由来自线程池的线程来执行的。
from("file:data/in").process(new MyValidator()).threads(20).process(new MyTransformation()).to("jpa:PurchaseOrder")
上图就不用详细说明了吧。