Tomcat源码分析(七)--单一启动/关闭机制(生命周

系统 2607 0
本系列转载自 http://blog.csdn.net/haitao111313/article/category/1179996   

在前面的大部分文章都是讲连接器和容器的,以后的内容会偏向写一些Tomcat的其他组件以及一些细节的东西。

   Tomcat有很多组件,要一个一个启动组件难免有点麻烦。由于Tomcat的包含关系是Catalina->Server->Service->容器/连接器/日志器等,于是可通过父组件负责启动/关闭它的子组件,这样只要启动Catalina,其他的都自动启动了。这种单一启动和关闭的机制是通过实现Lifecycle接口来实现的。下面是Lifecycle接口的定义:

  1. public   interface  Lifecycle {  
  2.      public   static   final  String START_EVENT =  "start" //生命周期的六个事件类型!   
  3.      public   static   final  String BEFORE_START_EVENT =  "before_start" ;  
  4.      public   static   final  String AFTER_START_EVENT =  "after_start" ;  
  5.      public   static   final  String STOP_EVENT =  "stop" ;  
  6.      public   static   final  String BEFORE_STOP_EVENT =  "before_stop" ;  
  7.      public   static   final  String AFTER_STOP_EVENT =  "after_stop" ;  
  8.    
  9.      public   void  addLifecycleListener(LifecycleListener listener); //在此组件中添加一个监听器   
  10.      public  LifecycleListener[] findLifecycleListeners();  
  11.      public   void  removeLifecycleListener(LifecycleListener listener);  
  12.      public   void  start()  throws  LifecycleException; //组件启动方法   
  13.      public   void  stop()  throws  LifecycleException;  
  14. }  

当组件实现了Lifecycle接口,父组件启动的时候,即调用start方法时,只要在父组件的start方法中也调用子组件的start方法即可(只有实现统一的接口Lifecycle才能实现统一调用,如以下调用方式:(Lifecycle)子组件.start()),下面一步一步来看源代码,首先在Catalina启动start,部分代码如下:

  1. // Start the new server   
  2.          if  (server  instanceof  Lifecycle) {  
  3.              try  {  
  4.                 server.initialize();  
  5.                 ((Lifecycle) server).start(); //启动server   
  6.                  try  {  
  7.                      // Register shutdown hook   
  8.                     Runtime.getRuntime().addShutdownHook(shutdownHook);  
  9.                 }  catch  (Throwable t) {  
  10.                      // This will fail on JDK 1.2. Ignoring, as Tomcat can run   
  11.                      // fine without the shutdown hook.   
  12.                 }  
  13.                  // Wait for the server to be told to shut down   
  14.                 server.await();  
  15.             }  catch  (LifecycleException e) {  
  16.                 System.out.println( "Catalina.start: "  + e);  
  17.                 e.printStackTrace(System.out);  
  18.                  if  (e.getThrowable() !=  null ) {  
  19.                     System.out.println( "----- Root Cause -----" );  
  20.                     e.getThrowable().printStackTrace(System.out);  
  21.                 }  
  22.             }  
  23.         }  
关键看((Lifecycle) server).start();这样便在启动Catalina的时候启动了Server,再看StandardServer的start方法:

  1. public   void  start()  throws  LifecycleException {  
  2.   
  3.      // Validate and update our current component state   
  4.      if  (started)  
  5.          throw   new  LifecycleException  
  6.             (sm.getString( "standardServer.start.started" ));  
  7.      // Notify our interested LifecycleListeners   
  8.      //发送这个事件   
  9.     lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,  null ); //发送生命周期事件。   
  10.   
  11.     lifecycle.fireLifecycleEvent(START_EVENT,  null );  
  12.     started =  true ;  
  13.   
  14.      // Start our defined Services   
  15.      synchronized  (services) {    //由这里也可以看出一个server可以有多个services   
  16.          for  ( int  i =  0 ; i < services.length; i++) {  
  17.              if  (services[i]  instanceof  Lifecycle)  
  18.                 ((Lifecycle) services[i]).start();  
  19.         }  
  20.     }  
  21.   
  22.      // Notify our interested LifecycleListeners   
  23.     lifecycle.fireLifecycleEvent(AFTER_START_EVENT,  null );  
  24.   
  25. }  
主要做了两件事,1:发送生命周期事件给监听者;2:启动子组件services(至于server怎么关联上services请看前面的几篇文章,以后都不再题怎么关联上的了)。

这里先岔开一下,说一下监听器,lifecycle是一个工具类LifecycleSupport的实例,每一个组件都有这样一个工具类,这个工具类的作用就是帮助管理该组件上的监听器,包括添加监听器和群发事件给监听器,看LifecycleSupport类的一些关键代码:

  1. public   final   class  LifecycleSupport {  
  2. public  LifecycleSupport(Lifecycle lifecycle) {  
  3.   
  4.          super ();  
  5.          this .lifecycle = lifecycle;  
  6.   
  7.     }  
  8.    private  LifecycleListener listeners[] =  new  LifecycleListener[ 0 ];  
  9.   public   void  addLifecycleListener(LifecycleListener listener) {  //向listeners添加监听器   
  10.   
  11.        synchronized  (listeners) {  
  12.           LifecycleListener results[] =  
  13.              new  LifecycleListener[listeners.length +  1 ];  
  14.            for  ( int  i =  0 ; i < listeners.length; i++)  
  15.               results[i] = listeners[i];  
  16.           results[listeners.length] = listener;  
  17.           listeners = results;  
  18.       }  
  19.   
  20.     }  
  21.   public   void  fireLifecycleEvent(String type, Object data) { //群发事件给监听器   
  22.   
  23.         LifecycleEvent event =  new  LifecycleEvent(lifecycle, type, data);  
  24.         LifecycleListener interested[] =  null ;  
  25.          synchronized  (listeners) {  
  26.             interested = (LifecycleListener[]) listeners.clone();  
  27.         }  
  28.          for  ( int  i =  0 ; i < interested.length; i++)  
  29.             interested[i].lifecycleEvent(event); //发送组件生命周期事件。   
  30.   
  31.     }  
  32. }  
先看构造方法,传入一个lifecycle,因为每个组件都实现了lifecycle,所以这里传入的实际上是一个组件,即每个组件都有一个LifecycleSupport与之关联,当要在组件中添加一个监听器的时候,实际上是添加进工具类LifecycleSupport的一个监听器数组listeners中,当要发送一个组件生命周期的事件时,工具类就会遍历监听器数组,然后再一个一个的发送事件。这里需要先实现我们自己的监听器类并且添加进我们需要监听的组件当中。实现监听器类只要实现LifecycleListener接口就行,这个接口只有一个方法:

  1. public   interface  LifecycleListener {  
  2.      public   void  lifecycleEvent(LifecycleEvent event);  
  3. }  

我们需要做的就是实现LifecycleListener接口来拥有自己的监听器,在lifecycleEvent方法里写自己监听到事件后该做的事情,然后添加进要监听的组件就行,比如当我们要看StandardServer是否启动了,在上面StandardServer的start方法有一句这样的代码:lifecycle.fireLifecycleEvent(START_EVENT, null);即发送StandardServer启动的事件给跟它关联的监听器。接下来回到一开始,当server启动后,接着启动它的子组件service,即调用StandardService的start方法,这个方法跟StandardServer的start方法差不多,只是启动了连接器和容器,连接器的start方法在前面的文章已经讲过了,主要是启动了n个处理器HttpProcessor组件。顶级容器是StandardEngine,它的start方法仅仅调用了父类ContainerBase的start方法,下面看ContainerBase的start方法:

  1. public   synchronized   void  start()  throws  LifecycleException {  
  2.   
  3.       // Validate and update our current component state   
  4.       if  (started)  
  5.           throw   new  LifecycleException  
  6.              (sm.getString( "containerBase.alreadyStarted" , logName()));  
  7.   
  8.       // Notify our interested LifecycleListeners   
  9.      lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,  null );  
  10.   
  11.      addDefaultMapper( this .mapperClass);  
  12.      started =  true ;  
  13.   
  14.       // Start our subordinate components, if any   
  15.       if  ((loader !=  null ) && (loader  instanceof  Lifecycle))  //启动所有其他的组件   
  16.          ((Lifecycle) loader).start();  
  17.       if  ((logger !=  null ) && (logger  instanceof  Lifecycle))  
  18.          ((Lifecycle) logger).start();  
  19.       if  ((manager !=  null ) && (manager  instanceof  Lifecycle))  
  20.          ((Lifecycle) manager).start();  
  21.       if  ((cluster !=  null ) && (cluster  instanceof  Lifecycle))  
  22.          ((Lifecycle) cluster).start();  
  23.       if  ((realm !=  null ) && (realm  instanceof  Lifecycle))  
  24.          ((Lifecycle) realm).start();  
  25.       if  ((resources !=  null ) && (resources  instanceof  Lifecycle))  
  26.          ((Lifecycle) resources).start();  
  27.   
  28.       // Start our Mappers, if any   
  29.      Mapper mappers[] = findMappers();  
  30.       for  ( int  i =  0 ; i < mappers.length; i++) {  
  31.           if  (mappers[i]  instanceof  Lifecycle)  
  32.              ((Lifecycle) mappers[i]).start();  
  33.      }  
  34.   
  35.       // Start our child containers, if any   
  36.      Container children[] = findChildren();  
  37.       for  ( int  i =  0 ; i < children.length; i++) {  
  38.           if  (children[i]  instanceof  Lifecycle)  
  39.              ((Lifecycle) children[i]).start();  
  40.      }  
  41.   
  42.       // Start the Valves in our pipeline (including the basic), if any   
  43.       if  (pipeline  instanceof  Lifecycle)  
  44.          ((Lifecycle) pipeline).start();  
  45.   
  46.       // Notify our interested LifecycleListeners   
  47.      lifecycle.fireLifecycleEvent(START_EVENT,  null );  
  48.   
  49.       // Notify our interested LifecycleListeners   
  50.      lifecycle.fireLifecycleEvent(AFTER_START_EVENT,  null );  
  51.   
  52.  }  

这里代码比较丰富,由它启动了Tomcat其他所有的组件,包括加载器,映射器,日志记录器,管道等等,由这里也可以看出,他们都实现了Lifecycle接口。统一关闭跟统一启动的逻辑差不多,这里就不再说了。至此,我们对Tomcat怎么实现统一启动/关闭应该有一个比较清晰的认识了!

Tomcat源码分析(七)--单一启动/关闭机制(生命周期)


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论