个人认为Camel中最重要的两大块,一是路由的构建过程,二是路由构建完成后的执行过程。
下面就参数前面的Camel示例来说说路由的构建细节。
其实这里说的路由构建其实是构建路由定义,对应Camel中的RouteDefinition类,一个RouteDefinition对象规定了或者说指定了一个消息从哪里产生,中间要经过什么样的处理,最后路由到什么地方。RouteDefinition有点类似java中的Class类,包含的都是一个元信息,外界则是参照这些元信息进行工作。RouteDefinition由RouteBuilder进行构建,再具体点就是调用RouteBuilder的configure()方法,构建完成后再添加到CamelContext中,那么该路由定义就可以运行了。RouteBuilder的configure()方法是一个抽象方法,所以该方法要由开发者进行实现,其实就是在进行路由定义的构建过程。下面是前面Camel示例中configure()中的代码:
camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { this.from("file:H:/temp/in").process(new Processor() { @Override public void process(Exchange exchange) throws Exception { GenericFile<File> gf = exchange.getIn().getBody(GenericFile.class); File file = gf.getFile(); PrintStream ps = new PrintStream(System.out); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String line = null; while((line=br.readLine())!=null) { ps.println(line); } ps.close(); br.close(); } }).to("file:H:/temp/out"); } });
路由定义的起始都是调用RouteBuilder的from方法,from方法有多个重载方法,一种是传入一个uri字符串,另一种是传入一个Endpoint对象,看到这种形式的重载就应该能想到,给定一个uri字符串最终肯定也是要获取一个Endpoint对象的,而在上一篇Camel查找组件方式中讲到Camel要根据uri解析出组件名称,再由组件名称查找出组件,在Camel中的重要概念中知道,组件其实是一个Endpoint工作,其作用就是创建出Endpoint对象的。到这里Camel根据uri字符串获取Endpoint对象这条线应该是通了的。
下面我们去看一个RouteBuilder的from(uri)方法,因为该方法用得最普遍:
public RouteDefinition from(String uri) { getRouteCollection().setCamelContext(getContext()); RouteDefinition answer = getRouteCollection().from(uri); configureRoute(answer); return answer; }
首先调用了getRouteCollection()方法,该方法返回一个RoutesDefinition对象,该对象代表的是多个路由定义的集合,因为Camel中可以运行多个路由定义。然后将CamelContext对象设置到RoutesDefinition中,然后调用RoutesDefinition的from(uri)方法:
public RouteDefinition from(String uri) { //创建RouteDefinition对象 RouteDefinition route = createRoute(); route.from(uri); return route(route); } protected RouteDefinition createRoute() { //创建RouteDefinition对象 RouteDefinition route = new RouteDefinition(); ErrorHandlerFactory handler = getErrorHandlerBuilder(); if (handler != null) {//为RouteDefinition设置错误处理器 route.setErrorHandlerBuilderIfNull(handler); } return route; }
RouteDefinition创建出来后又调用了RouteDefinition的from(uri)方法:
public RouteDefinition from(String uri) { //创建一个FromDefinition对象,并将其添加到路由定义的输入当中 getInputs().add(new FromDefinition(uri)); //返回当前RouteDefinition对象 return this; }
在RouteDefinition的from(uri)方法调用完成后再调用RoutesDefinition的route方法:
public RouteDefinition route(RouteDefinition route) { //预处理RouteDefinition,设置一些异常处理器,拦截器等 RouteDefinitionHelper.prepareRoute(getCamelContext(), route, getOnExceptions(), getIntercepts(), getInterceptFroms(), getInterceptSendTos(), getOnCompletions()); //将预处理好的RouteDefinition添加到RouteDefinition集合当中,这样Camel就知道多了一个路由定义 getRoutes().add(route); //标记该路由定义已处理好 route.markPrepared(); //返回当前的RouteDefinition对象 return route; }
RoutesDefinition的route方法调用完成后调用configureRoute方法,该方法只是为路由定义了设置了group属性值。
根据上面的分析,RouteBuilder的from方法就要是创建了一个RouteDefinition对象,并在该对象的输入中加入了一个FromDefinition对象,然后将该RouteDefinition对象添加进RoutesDefinition。
接下来调用了RouteDefinition的process方法,该定义定义在ProcessorDefinition类中,RouteDefinition从ProcessorDefinition继承到该方法,注意该方法的返回值为一泛型,该方法接收一个Processor类型参数:
public Type process(Processor processor) { ProcessDefinition answer = new ProcessDefinition(processor); addOutput(answer); //这时的this不是ProcessDefinition对象,而是RouteDefinition对象 return (Type) this; }
该方法很简单,创建出一个ProcessDefinition对象并添加进RouteDefinition的输出(outputs)中,最后返回RouteDefinition对象。
接下来调用RouteDefinition的to方法,该方法也是从从ProcessorDefinition继承而来,返回值也为一泛型:
public Type to(String uri) { addOutput(new ToDefinition(uri)); return (Type) this; }
该方法也很简单,创建一个ToDefinition对象并添加进RouteDefinition的输出(outputs)中。
至此,在这个简单示例中,整个路由定义就构建完成了,其实该路由定义最重要的就是输入与输出,输入与输出都可以有多个,默认情况下,在路由运行后,Camel会依赖调用这些输出处理器并最终将消息路由到指定目的地。