Tomcat源码分析(二) -- BootStrap的初始化

387 阅读2分钟

BootStrap的初始化

静态代码块

//这里主要是设置工作目录catalinaBaseFile和安装目录catalinaHomeFile
//默认情况下这两个都是同一个目录
static {
    // Will always be non-null
    String userDir = System.getProperty("user.dir");
    // Home first
    String home = System.getProperty(Globals.CATALINA_HOME_PROP);
    File homeFile = null;
    if (home != null) {
        File f = new File(home);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }
    if (homeFile == null) {
        // First fall-back. See if current directory is a bin directory
        // in a normal Tomcat install
        File bootstrapJar = new File(userDir, "bootstrap.jar");
        if (bootstrapJar.exists()) {
            File f = new File(userDir, "..");
            try {
                homeFile = f.getCanonicalFile();
            } catch (IOException ioe) {
                homeFile = f.getAbsoluteFile();
            }
        }
    }
    if (homeFile == null) {
        // Second fall-back. Use current directory
        File f = new File(userDir);
        try {
            homeFile = f.getCanonicalFile();
        } catch (IOException ioe) {
            homeFile = f.getAbsoluteFile();
        }
    }
    catalinaHomeFile = homeFile;
    System.setProperty(
        Globals.CATALINA_HOME_PROP, catalinaHomeFile.getPath());
    // Then base
    String base = System.getProperty(Globals.CATALINA_BASE_PROP);
    if (base == null) {
        catalinaBaseFile = catalinaHomeFile;
    } else {
        File baseFile = new File(base);
        try {
            baseFile = baseFile.getCanonicalFile();
        } catch (IOException ioe) {
            baseFile = baseFile.getAbsoluteFile();
        }
        catalinaBaseFile = baseFile;
    }
    System.setProperty(
        Globals.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
}

BootStrap的入口--main方法

public static void main(String args[]) {
    synchronized (daemonLock) {
        if (daemon == null) {
            // Don't set daemon until init() has completed
            //创建一个Bootstrap对象
            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";
            //启动时先load再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();
            if (null == daemon.getServer()) {
                System.exit(1);
            }
        } 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);
    }
}

BootStrap的init方法

public void init() throws Exception {
    //这里初始化了三个类加载器
    //    ClassLoader commonLoader = null;
    //    ClassLoader catalinaLoader = null;
    //    ClassLoader sharedLoader = null;
    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");
    //通过反射创建 Catalina 对象
    Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
    Object startupInstance = startupClass.getConstructor().newInstance();

    // Set the shared extensions class loader
    if (log.isDebugEnabled())
        log.debug("Setting startup class properties");
    //通过反射为上面创建的 Catalina 对象设置类加载器 sharedLoader
    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);
    //设置启动实例为 Catalina 对象,后续操作都是通过它来进行的
    catalinaDaemon = startupInstance;
}
  • 初始化了三个类加载器
  • 通过反射实例化了Catalina对象

BootStrap的load方法

private void load(String[] arguments) throws Exception {
    // Call the load() method
    //获取load方法名
    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;
    }
    //获取catalina对象的load方法对象
    Method method =
        catalinaDaemon.getClass().getMethod(methodName, paramTypes);
    if (log.isDebugEnabled()) {
        log.debug("Calling startup class " + method);
    }
    //反射调用catalina对象的load方法
    method.invoke(catalinaDaemon, param);
}

BootStarp的satart方法

public void start() throws Exception {
    //如果未被初始化,先调用初始化方法
    if (catalinaDaemon == null) {
        init();
    }
    //通过反射调用 Catalina 对象的 start 方法
    Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
    method.invoke(catalinaDaemon, (Object [])null);
}

BootStarp的stop方法

public void stop() throws Exception {
    //通过反射调用catalina的stop方法
    Method method = catalinaDaemon.getClass().getMethod("stop", (Class []) null);
    method.invoke(catalinaDaemon, (Object []) null);
}

小结

  • 可以看出BootStarp对象所有的操作都是基于 Catalina 对象来完成的
  • BootStrap 通过反射创建Catalina 对象,通过反射调用 Catalina 对象的方法
  • BootStrap 中初始化了三个类加载器