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

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

http://www.cnblogs.com/huangfox/archive/2011/10/20/2218970.html

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

Tomcat 学习进阶历程之Tomcat启动过程分析_第1张图片

如上图,实际调用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 方法在最后调用了 server initialize 方法。在 Tomcat Server 接口的标准实现是 StandardServer 。具体是那个实现类,就看 Catalina createStartDigester方法里面定义的了。 StandardServer initialize 方法对其子组件 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启动过程分析_第2张图片

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

你可能感兴趣的:(TOMCAT进阶历程,Tomcat,TOMCAT进阶历程,bootstrap,tomcat,catalina.bat)