现在的位置: 首页 > 综合 > 正文

Tomcat启动过程分析

2017年12月07日 ⁄ 综合 ⁄ 共 3739字 ⁄ 字号 评论关闭

 

先来看看Tomcat的架构吧:


本文将介绍Tomcat启动时涉及到的组件和初始化,启动过程。

1:Tomcat启动从org.apache.catalina.startup的main()函数开始。

public static void main(String args[]) {

        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }

        .....此处省略部分代码...
                daemon.load(args);
                daemon.start();
        .....此处省略部分代码...

    }

此处看到启动过程涉及到3个函数:init(),load(),start()。先来分析一下init()吧。

public void init()
        throws Exception
    {
.....此处省略部分代码.......

        initClassLoaders();

.....此处省略部分代码.......
//下面通过反射机制调用Catalina的setParentClassLoader方法
        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 = startupInstance;

    }
private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

initClassLoaders() 初始化了三个类加载器。接下来catalina就可以用这三种类型的classLoader来负责装配容器了。

接下来是load()方法。它其实会通过反射机制去执行catalina的load()方法。

public void load() {
//……
        //初始化Digester组件,定义了解析规则
        Digester digester = createStartDigester();
        //……中间略去代码若干,主要作用为将server.xml文件转换为输入流
        try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
//通过Digester解析这个文件,在此过程中会初始化各个组件实例及其依赖关系
            digester.parse(inputSource);
            inputStream.close();
        } catch (Exception e) {
          
        }
        // 调用Server的initialize方法,初始化各个组件
        if (getServer() instanceof Lifecycle) {
            try {
                getServer().initialize();
            } catch (LifecycleException e) {
                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                    throw new java.lang.Error(e);
                else   
                    log.error("Catalina.start", e);
                
            }
        }

    } 

可以看出load的两个任务:使用Digester组件按照给定的规则解析server.xml、调用Server的initialize方法。这里的Server是从StandardService中的getServer()得来的。让我们进入Server的init()中吧。init()------>initialize()。

public void initialize()
        throws LifecycleException 
    {
......此处省略部分代码......
        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
        initialized = true;

......此处省略部分代码......
        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) {
            services[i].initialize();
        }
    }

如果你还有兴趣追溯下去的话,你会发现services的initialize()中还会进行connector的初始化等。这样就能完成各级组件的初始化。

接下来是start()函数了。

public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }

可以看出还是通过反射机制调用catalina的start()方法。

public void start() {
......此处省略部分代码......
        
        // Start the new server
        if (getServer() instanceof Lifecycle) {
            try {
                ((Lifecycle) getServer()).start();
            } catch (LifecycleException e) {
                log.error("Catalina.start: ", e);
            }
        }
 ......此处省略部分代码......

        try {
            // Register shutdown hook
            if (useShutdownHook) {
                if (shutdownHook == null) {
                    shutdownHook = new CatalinaShutdownHook();
                }
                Runtime.getRuntime().addShutdownHook(shutdownHook);
                
 ......此处省略部分代码......

    }

当你看到了

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

这段代码时,你很容易联想到我们之前的load方法,当时是采用级联方式的进行load的。同样这里也是那样。不断的通过级联进行start。那么service,Engine,Host,Connector等组件容器都会启动。shutdownHook 是我们注册的一个Hook。tomcat中提供了hook,可以在关闭过程中运行一些代码,执行清理的工作。shutdown
hook是一个java.lang.Thread子类的实例,shutdown hook会由jvm启动,不用你自己启动。

protected class CatalinaShutdownHook extends Thread {

        public void run() {
            ......此处省略部分代码......
        }

    }

这样就完成了整个Tomcat的启动了。当客户端有请求进来了,就可以通过connector等组件的配合完成整个的请求处理。

抱歉!评论已关闭.