当前位置: > Linux服务器 > Tomcat >

Tomcat 学习进阶历程之Tomcat启动过程分析

时间:2014-12-25 17:15来源:linux.it.net.cn 作者:IT

本节通过跟踪Tomcat的源码来分析Tomcat是如何启动及装配各个组件的。最好下载Tomcat的源码导入到Eclipse,这样方便跟踪。方法可参考:

http://linux.it.net.cn/e/server/Tomcat/2014/1225/10741.html

Tomcat的启动脚本篇,我们分析过,当执行Start.bat文件时,最后实际调用的是BootStrap.java类。如下图:

启动类调用

 

如上图,实际调用BootStrap,并传递一个名为‘start’参数。

BootStrap的主方法main中,主要做了一下几件事情: 

1、实例化一个BootStrap,并调用其init方法。

2、调用load方法。

3、调用start方法。

init方法中,BootStrap完成了一件重要的工作,就是根据Java反射,实例化了一个org.apache.catalina.startup.Catalina类。Init的主要代码如下:


  1. initClassLoaders();//初始化catalinaLoader  
  2.         Thread.currentThread().setContextClassLoader(catalinaLoader);  
  3.         SecurityClassLoad.securityClassLoad(catalinaLoader);  
  4.         // Load our startup class and call its process() method  
  5.         if (log.isDebugEnabled())  
  6.             log.debug("Loading startup class");  
  7.         Class startupClass =  
  8.             catalinaLoader.loadClass  
  9.             ("org.apache.catalina.startup.Catalina");  
  10.         Object startupInstance = startupClass.newInstance();  
  11.         // Set the shared extensions class loader  
  12.         if (log.isDebugEnabled())  
  13.             log.debug("Setting startup class properties");  
  14.         String methodName = "setParentClassLoader";  
  15.         Class paramTypes[] = new Class[1];  
  16.         paramTypes[0] = Class.forName("java.lang.ClassLoader");  
  17.         Object paramValues[] = new Object[1];  
  18.         paramValues[0] = sharedLoader;  
  19.         Method method =  
  20.             startupInstance.getClass().getMethod(methodName, paramTypes);  
  21.         method.invoke(startupInstance, paramValues);  
  22. //catalinaDaemon是BootStrap类的一个私有变量  
  23.         catalinaDaemon = startupInstance;  

BootStrapload方法,通过反射,调用Catalina类的load方法。在Catalina类的load方法中完成了一项极其重要的工作,就是通过Apache的另一项开源项目Digester来解析Tomcat的核心配置文件:conf/server.xml Digester作用是讲XML转成指定的Java对象Catalina类的load方法的具体工作下面会介绍到。

再说BootStrapstart方法,主要是调用Catalina类的start方法。

通过对BootStrap三个方法的分析可以看到,BootStrap类启动时的主要工作就是实例化Catalina,调用其load方法与start方法。并且这些操作都是在BootStrap类中通过Java反射机制来完成的。

前面提到了Catalinaload方法通过Apache的另一项开源项目Digester来解析Tomcat的核心配置文件:conf/server.xmlCatalina定义了一个名为createStartDigester的方法,此方法根据server.xml的结构,定义了一套解析Server.xml文件的柜子,并返回一个实例化的Digester。在load方法使用返回的Digester示例加载server.xml配置文件,并进行解析。Load方法的主要代码如下:


  1. Digester digester = createStartDigester();  
  2.         InputSource inputSource = null;  
  3.         InputStream inputStream = null;  
  4.         try {  
  5.             file = configFile();//根据catalina.base路径获取server.xml文件  
  6.             inputStream = new FileInputStream(file);  
  7.             inputSource = new InputSource("file://" + file.getAbsolutePath());  
  8.         } catch (Exception e) {  
  9.             ;  
  10.         }  
  11. //…….略去一些源码  
  12.         try {  
  13.             inputSource.setByteStream(inputStream);  
  14. //Catalina将自身设置进digester  
  15.             digester.push(this);  
  16.             digester.parse(inputSource);  
  17.             inputStream.close();  
  18.         } catch (Exception e) {  
  19.             log.warn("Catalina.start using "  
  20.                                + getConfigFile() + ": " , e);  
  21.             return;  
  22.         }  
  23. getServer().initialize();//初始化Server  

load方法中,通过调用digester.push(this); Catalina将自身设置进digester,这样通过digester.parse方法解析后,Catalina对象的各个属性将被实例化并填充。最关键的是实例化了Server对象。实际上digester实例化了ServiceConnectorEngineHostcontext等各种组件,并相应的设置了各个组件的关系。

Load方法在最后调用了serverinitialize方法。在TomcatServer接口的标准实现是StandardServer。具体是那个实现类,就看CatalinacreateStartDigester方法里面定义的了。StandardServerinitialize方法对其子组件service进行了初始化。

 


 
  1. // Initialize our defined Services  
  2.         for (int i = 0; i < services.length; i++) {  
  3.             services[i].initialize();  
  4.         }  

 

ServiceTomcat中的标准实现是StandardService。其initialize方法主要代码如下:


 
  1. synchronized (connectors) {  
  2.            for (int i = 0; i < connectors.length; i++) {  
  3.                try {  
  4.                    connectors[i].initialize();  
  5.                } catch (Exception e) {  
  6.                    String message = sm.getString(  
  7.                            "standardService.connector.initFailed",  
  8.                            connectors[i]);  
  9.                    log.error(message, e);  
  10.                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))  
  11.                        throw new LifecycleException(message);  
  12.                }  
  13.            }  
  14.        }  

可以看到Serviceinitialize主要工作就是调用connectorinitialize方法。

同理Connector会依次处理其下的其他组件,这里不再依次列入。

让我们回到Catalina,再看看它的start方法:


 
  1. if (getServer() instanceof Lifecycle) {  
  2.             try {  
  3.                 ((Lifecycle) getServer()).start();  
  4.             } catch (LifecycleException e) {  
  5.                 log.error("Catalina.start: ", e);  
  6.             }  
  7.         }  

StandardServerstart方法关键代码如下:


 
  1. synchronized (services) {  
  2.             for (int i = 0; i < services.length; i++) {  
  3.                 if (services[i] instanceof Lifecycle)  
  4.                     ((Lifecycle) services[i]).start();  
  5.             }  
  6.         }  

同样的StandardService会依次启动其下的其他组件,此处不再依次列出。

CatalinaStart方法执行完,表明Tomcat已经配置好自身,可以对外工作了。整个启动时序图如下:

启动时序图



(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容