规则引擎(Apache camel) 学习七

1.循环动态路由 Dynamic Router

   介绍:动态循环路由的特点是开发人员可以通过条件表达式等方式,动态决定下一个路由位置。

             在下一路由位置处理完成后Exchange将被重新返回到路由判断点,并由动态循环路由再次做出新路径的判断。

            如此循环执行直到动态循环路由不能再找到任何一条新的路由路径为止。

            下图来源于官网,展示了动态循环路由的工作效果:

             

 

         这里可以看出动态循环路由(dynamicRouter)和之前介绍的动态路由(recipientList)在工作方式上的差异。

        dynamicRouter一次选择只能确定一条路由路径,而recipientList只进行一次判断并确定多条路由分支路径;

        dynamicRouter确定的下一路由在执行完成后,Exchange对象还会被返回到dynamicRouter中以便开始第二次循环判断,

        而recipientList会为各个分支路由复制一个独立的Exchange对象,并且各个分支路由执行完成后

        Exchange对象也不会返回到recipientList;下面我们还是通过源代码片段,向各位读者展示dynamicRouter的使用方式。

        在代码中,我们编排了三个路由DirectRouteA主要负责通过Http协议接收处理请求,并执行dynamicRouter。

        DirectRouteB和DirectRouteC两个路由是可能被dynamicRouter选择的分支路径:

               DirectRouteA:

                  /**
                     * 第一个路由,主要用于定义整个路由的起点
                     * 通过Http协议接收处理请求
                     * @author yinwenjie
                     */
                     public class DirectRouteA extends RouteBuilder {

                            /* (non-Javadoc)
                             * @see org.apache.camel.builder.RouteBuilder#configure()
                             */
                            @Override
                            public void configure() throws Exception {
                                 from("jetty:http://0.0.0.0:8282/dynamicRouterCamel")
                                 // 使用dynamicRouter,进行“动态路由”循环,
                                 // 直到指定的下一个元素为null为止
                                .dynamicRouter().method(this, "doDirect")
                                .process(new OtherProcessor());
                            }

                            /**
                              * 该方法用于根据“动态循环”的次数,确定下一个执行的Endpoint
                              * @param properties 通过注解能够获得的Exchange中properties属性,可以进行操作,并反映在整个路由过程中
                              * @return
                              */
                              public String doDirect(@Properties Map<String, Object> properties) {
                                   // 在Exchange的properties属性中,取出Dynamic Router的循环次数
                                   AtomicInteger time = (AtomicInteger)properties.get("time");
                                   if(time == null) {
                                       time = new AtomicInteger(0);
                                       properties.put("time", time);
                                    } else {
                                       time = (AtomicInteger)time;
                                }
                         LOGGER.info("这是Dynamic Router循环第:

                        【" + time.incrementAndGet() + "】次执行!执行线程:" + Thread.currentThread().getName());

                          // 第一次选择DirectRouteB
                          if(time.get() == 1) {
                              return "direct:directRouteB";
                           }
                          // 第二次选择DirectRouteC
                          else if(time.get() == 2) {
                               return "direct:directRouteC";
                           }
                         // 第三次选择一个Log4j-Endpoint执行
                        else if(time.get() == 3) {
                                return "log:DirectRouteA?showExchangeId=true&showProperties=ture&showBody=false";
                          }

                         // 其它情况返回null,终止 dynamicRouter的执行
                         return null;
                      }
                   }

            过程: 在DirectRouteA中我们使用“通过一个method方法返回信息”的方式确定dynamicRouter“动态循环路由”的下一个Endpoint。

                        当然在实际使用中,开发人员还可以有很多方式向dynamicRouter“动态循环路由”返回指定的下一Endpoint。

                         例如使用JsonPath指定JSON格式数据中的某个属性值,或者使用XPath指定XML数据中的某个属性值,

                         又或者使用header方法指定Exchange中Header部分的某个属性。但是无论如何请开发人员确定一件事情:

                          向dynamicRouter指定下一个Endpoint的方式中是会返回null进行循环终止的,否则整个dynamicRouter会无限的执行下去。

 

            总结: 以上doDirect方法中,我们将一个计数器存储在了Exchange对象的properties区域,

                       以便在同一个Exchange对象执行doDirect方法时进行计数操作。当同一个Exchange对象第一次执行动态循环路由判断时,

                        选择directRouteB最为一下路由路径;当Exchange对象第二次执行动态循环路由判断时,选择DirectRouteC作为下一路由路径;

                       当Exchange对象第三次执行时,选择一个Log4j-Endpoint作为下一个路由路径;当Exchange对象第四次执行时,

                       作为路由路径判断的方法doDirect返回null,以便终止dynamicRouter的执行。

 

              注:不能在DirectRouteA类中定义一个全局变量作为循环路由的计数器,

                      因为由Jetty-HttpConsumer生成的线程池中,线程数量和线程对象是固定的,

                      并且Camel也不是为每一个Exchange对象的运行创建新的DirectRouteA对象实例。

                      所以如果在DirectRouteA类中定义全局变量作为循环路由的计数器,各位读者自己想想会发生什么样的结果吧。别骂娘……

           

             DirectRouteB 和 DirectRouteC

                    /**
                      * 这是另一条路由分支
                      * @author yinwenjie
                      */
                    public class DirectRouteC extends RouteBuilder {
                              @Override
                              public void configure() throws Exception {
                                      from("direct:directRouteC")
                                      .to("log:DirectRouteC?showExchangeId=true&showProperties=ture&showBody=false");
                              }
                     }

           由于DirectRouteB和DirectRouteC两个路由定义的代码非常类似,所以这里只贴出其中一个。

           启动Camel应用程序,并将路由加入CamelContext

           ......
           public static void main(String[] args) throws Exception {
                   // 这是camel上下文对象,整个路由的驱动全靠它了。
                   ModelCamelContext camelContext = new DefaultCamelContext();
                    // 启动route
                    camelContext.start();
                    // 将我们编排的一个完整消息路由过程,加入到上下文中
                    DynamicRouterCamel dynamicRouterCamel = new DynamicRouterCamel();
                    camelContext.addRoutes(dynamicRouterCamel.new DirectRouteA());
                    camelContext.addRoutes(dynamicRouterCamel.new DirectRouteB());
                    camelContext.addRoutes(dynamicRouterCamel.new DirectRouteC());

                     // 通用没有具体业务意义的代码,只是为了保证主线程不退出
                     synchronized (DynamicRouterCamel.class) {
                                  DynamicRouterCamel.class.wait();
                     }
             }
             ......

       运行效果

          [2016-06-27 20:44:52] INFO qtp1392999621-16 这是Dynamic Router循环第:

        【1】次执行!执行线程:qtp1392999621-16           (DynamicRouterCamel.java:105)

         [2016-06-27 20:44:56] INFO qtp1392999621-16 Exchange[Id: ID-yinwenjie-240-57818-1467030193866-0-3,

         ExchangePattern: InOut, BodyType: org.apache.camel.converter.stream.InputStreamCache] (MarkerIgnoringBase.java:96)

         [2016-06-27 20:44:56] INFO qtp1392999621-16 这是Dynamic Router循环第:

       【2】次执行!执行线程:qtp1392999621-16 (DynamicRouterCamel.java:105)

         [2016-06-27 20:44:56] INFO qtp1392999621-16 Exchange[Id: ID-yinwenjie-240-57818-1467030193866-0-3,

         ExchangePattern: InOut, BodyType: org.apache.camel.converter.stream.InputStreamCache] (MarkerIgnoringBase.java:96)

         [2016-06-27 20:44:56] INFO qtp1392999621-16 这是Dynamic Router循环第:

       【3】次执行!执行线程:qtp1392999621-16 (DynamicRouterCamel.java:105)

        [2016-06-27 20:44:56] INFO qtp1392999621-16 Exchange[Id: ID-yinwenjie-240-57818-1467030193866-0-3,

        ExchangePattern: InOut, BodyType: org.apache.camel.converter.stream.InputStreamCache] (MarkerIgnoringBase.java:96)

        [2016-06-27 20:44:56] INFO qtp1392999621-16 这是Dynamic Router循环第:

      【4】次执行!执行线程:qtp1392999621-16 (DynamicRouterCamel.java:105)

       [2016-06-27 20:44:56] INFO qtp1392999621-16 最后exchangeID = ID-yinwenjie-240-57818-1467030193866-0-3 |               

      org.apache.camel.converter.stream.InputStreamCache@2abaa89c ||

      被OtherProcessor处理 | time = 4 (DynamicRouterCamel.java:150)

    总结:从以上执行效果看,无论dynamicRouter执行的是第几次循环判断,

               Exchange都是同一个(ID号为【ID-yinwenjie-240-57818-1467030193866-0-3】)。

 

学习来源:http://www.uml.org.cn/zjjs/201801224.asp?artid=20341

 

posted @ 2020-08-26 17:16  小窝蜗  阅读(953)  评论(0编辑  收藏  举报