Tomcat7启动分析(二)Bootstrap类中的main方法

之前分析了Tomcat的启动脚本,如果从startup.bat开始启动Tomcat的话会发现最后会调用org.apache.catalina.startup.Bootstrap里的main方法,并且传过来的最后一个命令行参数是start,接下来的启动代码分析就从这里开始。

 

先看下这个main方法的代码:

/**
     * Main method and entry point when starting Tomcat via the provided
     * scripts.
     *
     * @param args Command line arguments to be processed
     */
    public static void main(String args[]) {

        if (daemon == null) {
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            daemon = bootstrap;
        } else {
            // When running as a service the call to stop will be on a new
            // thread so make sure the correct class loader is used to prevent
            // a range of class not found exceptions.
            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            // Unwrap the Exception for clearer error reporting
            if (t instanceof InvocationTargetException &&
                    t.getCause() != null) {
                t = t.getCause();
            }
            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }

    }

这里的daemon是Bootstrap类中的一个静态成员变量,类型就是Bootstrap,第10行的注释已经说明在调用过init方法之后才会给该变量赋值,初始时将是null,所以首先将实例化一个Bootstrap对象,接着调用init方法,该方法代码如下:

/**
     * Initialize daemon.
     */
    public void init()
        throws Exception
    {

        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();

        initClassLoaders();

        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 = startupInstance;

    }

 这里不再逐句解释代码的作用,总的来说这个方法主要做了一下几件事:1.设置catalina.home、catalina.base系统属性,2.创建commonLoader、catalinaLoader、sharedLoader类加载器(默认情况下这三个类加载器指向同一个对象。建议看看createClassLoader方法,里面做的事情还挺多,比如装载catalina.properties里配置的目录下的文件和jar包,后两个加载器的父加载器都是第一个,最后注册了MBean,可以用于JVM监控该对象),3.实例化一个org.apache.catalina.startup.Catalina对象,并赋值给静态成员catalinaDaemon,以sharedLoader作为入参通过反射调用该对象的setParentClassLoader方法。

 

接下来去命令行最后一个参数,按文章开头所说是start,所以将执行34行到36行的代码,将会执行Bootstrap类中的load、start方法。

 

load方法代码如下:

    /**
     * Load daemon.
     */
    private void load(String[] arguments)
        throws Exception {

        // Call the load() method
        String methodName = "load";
        Object param[];
        Class<?> paramTypes[];
        if (arguments==null || arguments.length==0) {
            paramTypes = null;
            param = null;
        } else {
            paramTypes = new Class[1];
            paramTypes[0] = arguments.getClass();
            param = new Object[1];
            param[0] = arguments;
        }
        Method method =
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled())
            log.debug("Calling startup class " + method);
        method.invoke(catalinaDaemon, param);

    }

就是通过反射调用catalinaDaemon对象的load方法,catalinaDaemon对象在上面的init方法中已经实例化过了。

 

start方法与load方法相似,也是通过反射调用catalinaDaemon对象上的start方法:

    /**
     * Start the Catalina daemon.
     */
    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

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

    }

 

下面一篇文章将分析catalinaDaemon对象中的load、start两个方法,里面会涉及一个有趣的话题——Digester的使用。

你可能感兴趣的:(tomcat,源码分析)