首页 > 技术文章 > 规则引擎(Apache camel) 学习九

HuiShouGuoQu 2020-08-27 14:39 原文

1.DefaultCamelContext结构和启动过程

    介绍:如果我们翻阅DefaultCamelContext的源代码,首先就会发现在其中定义了许多全局变量,

               数量在70个左右(实际上根据《代码大全》的描述,一个类中不应该有这么多全局变量。

               究竟这个类的作者当时是怎样的想法,就不清楚了)。

              其中一些变量负责记录CamelContext的状态属性、一些负责引用辅助工具还有一些记录关联的顶层工作对象

            (例如Endpoint、Servcie、Routes、)Components等等)。

             很明显我们无法对这些变量逐一进行深入分析讲解,但是经过前两篇文章的介绍至少以下变量信息我们是需要理解其作用的。

     源码:

            public class DefaultCamelContext extends ServiceSupport

                implements ModelCamelContext, SuspendableService {
                         ......

                       // java的基础概念:类加载器,一般进行线程操作时会用到它
                       private ClassLoader applicationContextClassLoader;
                       // 已定义的endpoint URI(完整的)和Endpoint对象的映射关系
                       private Map<EndpointKey, Endpoint> endpoints;
                       // 已使用的组件名称(即Endpoint URI头所代表的组件名称)和组件对象的对应关系
                       private final Map<String, Component> components = new HashMap<String, Component>();
                       // 针对原始路由编排所分析出的路由对象,路由对象是作为CamelContext从路由中的一个元素传递到下一个元素的依据
                       // 路由对象中还包含了,将路由定义中各元素连接起来的其它Service。例如DefaultChannel
                       private final Set<Route> routes = new LinkedHashSet<Route>();
                       // 由DSL或者XML描述的原始路由编排。每一个RouteDefinition元素中都包含了参与这个路由的所有Service定义。
                       private final List<RouteDefinition> routeDefinitions = new ArrayList<RouteDefinition>();
                       // 生命周期策略,实际上是一组监听,文章后面的内容会重点讲到
                       private List<LifecycleStrategy> lifecycleStrategies = new CopyOnWriteArrayList<LifecycleStrategy>();
                       // 这是一个计数器,记录当前每一个不同的Routeid中正在运行的的Exchange数量
                      private InflightRepository inflightRepository = new DefaultInflightRepository();
                      // 服务停止策略
                      private ShutdownStrategy shutdownStrategy = new DefaultShutdownStrategy(this);
                      ......
               }

    总结:看来CamelContext是挺重要的,它基本将Camel应用程序运行所需要的所有基本信息都记录在案。

              另外,Apache Camel中还有一个名叫org.apache.camel.CamelContextAware的接口,

             只要实现该接口的就必须实现这个接口定义的两个方法:setCamelContext和getCamelContext。

            而实际上在Camel中的大多数元素都实现了这个接口,

            所以我们在阅读代码时可以发现DefaultCamelContext在一边启动各个Service的时候,

            顺便将自己所为参数赋给了正在启动的Service,最终实现了各个Service之间的共享上下文信息的效果:

                  // 这是CamelContextAware接口的定义
                  public interface CamelContextAware {
                      /**
                       * Injects the {@link CamelContext}
                      *
                      * @param camelContext the Camel context
                      */
                      void setCamelContext(CamelContext camelContext);

                     /**
                       * Get the {@link CamelContext}
                       *
                       * @return camelContext the Camel context
                      */
                    CamelContext getCamelContext();
                }

               ............

              // 这是DefaultCamelContext的doAddService方法中
             // 对实现了CamelContextAware接口的Service
             // 进行CamelContext设置的代码
            private void doAddService(Object object, boolean closeOnShutdown) throws Exception {
                   ......
                   if (object instanceof CamelContextAware) {
                        CamelContextAware aware = (CamelContextAware) object;
                        aware.setCamelContext(this);
                    }
                   ......
          }

 

    DefaultCamelContext的启动过程:

     DefaultCamelContext是如何帮助整个Camel应用程序中若干Service完成启动过程的?

     首先说明DefaultCamelContext 也是一个Service,所以它必须实现Service接口的start()方法和stop()方法。

     而DefaultCamelContext对于start()方法的实现就是“启动其它已知的Service”。

 

    更具体的来说,DefaultCamelContext将所有需要启动的Service按照它们的作用类型进行区分,

    例如负责策略管理的Service、负责Components组件描述的Service、负责注册管理的Service等等,

    然后再按照顺序启动这些Service。以下代码片段提取自DefaultCamelContext的doStartCamel()私有方法,

     并加入了笔者的中文注释(原有作者的注释依然保留),

     这个私有方法由DefaultCamelContext中的start()方法间接调用,用于完成上述各Service启动操作。

   源码:

          // 为了调用该私有方法,之前的方法执行栈分别为:
          // start()
          // super.start()
          // doStart()
         ......
         private void doStartCamel() throws Exception {
               // 获取classloader是有必要的,这样保证了Camel服务中的classloader和环境中的其他组件(例如spring)一致
              if (applicationContextClassLoader == null) {
                 // Using the TCCL as the default value of ApplicationClassLoader
                ClassLoader cl = Thread.currentThread().getContextClassLoader();
                if (cl == null) {
                      // use the classloader that loaded this class
                      cl = this.getClass().getClassLoader();
                 }
                setApplicationContextClassLoader(cl);
           }

          ......

          // 首先启动的是ManagementStrategy策略管理器,它的默认实现是DefaultManagementStrategy。
          // 还记得我们在分析DUBBO时提到的Java spi机制吧,Camel-Core也使用了这个机制,并进行了二次封装。详见org.apache.camel.spi代码包。
          // 启动ManagementStrategy,可以帮助Camel实现第三方组件包(例如Camel-JMS)的动态加载
          // start management strategy before lifecycles are started
          ManagementStrategy managementStrategy = getManagementStrategy();
          // inject CamelContext if aware
          if (managementStrategy instanceof CamelContextAware) {
               ((CamelContextAware) managementStrategy).setCamelContext(this);
           }
          ServiceHelper.startService(managementStrategy);

          ......
         // 然后启动的是 生命周期管理策略
         // 这个lifecycleStrategies变量是一个LifecycleStrategy泛型的List集合。
         // 实际上LifecycleStrategy是指是一组监听,详见代码片段后续的描述
         ServiceHelper.startServices(lifecycleStrategies);

          ......
          // 接着做一系列的Service启动动作
          // 首先是Endpoint注册管理服务,要进行重点介绍的是org.apache.camel.util.LRUSoftCache
          // 它使用了java.lang.ref.SoftReference进行实现,这是Java提供的
          endpoints = new EndpointRegistry(this, endpoints);
          addService(endpoints);

          ......
          // 启动线程池管理策略和一些列其它服务
          // 基本上这些Service已经在上文中提到过
         doAddService(executorServiceManager, false);
         addService(producerServicePool);
         addService(inflightRepository);
         addService(shutdownStrategy);
         addService(packageScanClassResolver);
         addService(restRegistry);

         ......
          // start components
          startServices(components.values());
          // 启动路由定义,路由定义RouteDefinition本身并不是Service,但是其中包含了参与路由的各种元素,例如Endpoint。
          // start the route definitions before the routes is started
          startRouteDefinitions(routeDefinitions);

          ......
      }
      ......

 

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

推荐阅读