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

来源:互联网 发布:阿里云服务器出现宕机 编辑:程序博客网 时间:2024/05/26 20:22

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

http://www.cnblogs.com/huangfox/archive/2011/10/20/2218970.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的主要代码如下:

initClassLoaders();//初始化catalinaLoader        Thread.currentThread().setContextClassLoader(catalinaLoader);        SecurityClassLoad.securityClassLoad(catalinaLoader);        // Load our startup class and call its process() method        if (log.isDebugEnabled())            log.debug("Loading startup class");        Class startupClass =            catalinaLoader.loadClass            ("org.apache.catalina.startup.Catalina");        Object startupInstance = startupClass.newInstance();        // Set the shared extensions class loader        if (log.isDebugEnabled())            log.debug("Setting startup class properties");        String methodName = "setParentClassLoader";        Class paramTypes[] = new Class[1];        paramTypes[0] = Class.forName("java.lang.ClassLoader");        Object paramValues[] = new Object[1];        paramValues[0] = sharedLoader;        Method method =            startupInstance.getClass().getMethod(methodName, paramTypes);        method.invoke(startupInstance, paramValues);//catalinaDaemon是BootStrap类的一个私有变量        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方法的主要代码如下:

Digester digester = createStartDigester();        InputSource inputSource = null;        InputStream inputStream = null;        try {            file = configFile();//根据catalina.base路径获取server.xml文件            inputStream = new FileInputStream(file);            inputSource = new InputSource("file://" + file.getAbsolutePath());        } catch (Exception e) {            ;        }//…….略去一些源码        try {            inputSource.setByteStream(inputStream);//Catalina将自身设置进digester            digester.push(this);            digester.parse(inputSource);            inputStream.close();        } catch (Exception e) {            log.warn("Catalina.start using "                               + getConfigFile() + ": " , e);            return;        }getServer().initialize();//初始化Server

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

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

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

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

 synchronized (connectors) {            for (int i = 0; i < connectors.length; i++) {                try {                    connectors[i].initialize();                } catch (Exception e) {                    String message = sm.getString(                            "standardService.connector.initFailed",                            connectors[i]);                    log.error(message, e);                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))                        throw new LifecycleException(message);                }            }        }

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

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

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

if (getServer() instanceof Lifecycle) {            try {                ((Lifecycle) getServer()).start();            } catch (LifecycleException e) {                log.error("Catalina.start: ", e);            }        }

StandardServerstart方法关键代码如下:

synchronized (services) {            for (int i = 0; i < services.length; i++) {                if (services[i] instanceof Lifecycle)                    ((Lifecycle) services[i]).start();            }        }

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

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

启动时序图

上一篇:Tomcat 学习进阶历程之Tomcat架构与核心类分析

0 0
原创粉丝点击