首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

tomcat7源码学习札记(启动篇)

2013-04-09 
tomcat7源码学习笔记(启动篇)一.将tomcat源码导入到eclipse??? 在apach官网上下载tomcat源码后,学习源码通

tomcat7源码学习笔记(启动篇)

一.将tomcat源码导入到eclipse

??? 在apach官网上下载tomcat源码后,学习源码通过导入到eclipse里,然后用其调试功能来学习是的方便。对于eclipse导入tomcat源码可以参考:http://www.cnblogs.com/huangfox/archive/2011/10/20/2218970.html 对于tomcat依赖的jar,可以通过后面的附件来下载。

?

?

二.运行tomcat

??? 首先,tomcat在启动时,会读取一些配置文件,也就是${CATALINA_HOME}/conf下面的所有配置文件,我们可以将conf文件夹及其里面的所有配置文件拷到eclipse中来,提供tomcat启动需要的配置信息。

??? 在org.apache.catalina.startup这个包下面的Bootstrap.java是启动tomcat的类,它里面有个main函数,是启动tomcat的入口,代码如下

?

/**     * 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);        }    }

??????? 通过上面源码可以看出,tomcat先进行初始化,主要进行的功能有:设置catalina的路径(主要有catalina.home和catalina.base这两个路径),初始化catalina的加载类(主要有三个类别:common.loader,server.loader,shared.loader,这些加载类都是通过读取conf下面的catalina.properties配置文件来获取相应的加载类,而且这些类加载都是通过tomcat里设置的安全验证的),设置catalina的(这个类的路径为:org.apache.catalina.startup.Catalina。其中默认加载类为org.apache.catalina.loader.StandardClassLoader,加载时需要的配置文件路径为:conf/server.xml)。?????? tomcat在初始化完上面的功能后,就根据启动时的命令参数,来进行相应命令的动作,通过上面的源码可以看出,在启动Bootstrap.java这个类时,可以传入的命令参数有:startd(默认值)、stopd、configtest,具体相应命令的功能,就不再进行说明。

?

?

三,分析init初始化哪些内容??

??? 下面来具体看看tomcat在启动时,都初始化了哪些内容。首先看一下init()这个方法的源码:

/**     * Initialize daemon.     */    public void init()         throws Exception    {        // Set Catalina path        setCatalinaHome();        log.info("catalina.home:" + System.getProperty(Globals.CATALINA_HOME_PROP));        setCatalinaBase();        log.info("catalina.base:" + System.getProperty(Globals.CATALINA_BASE_PROP));        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;    }

???

??? 3.1 catalina的两个路径设置

??? 其中,setCatalinaHome()和setCatalinaBase();这两个方法就是设置catalina的两个路径的,具体的实现,首先参看setCatalinaHome()方法的源码:

/**     * Set the <code>catalina.home</code> System property to the current     * working directory if it has not been set.     */    private void setCatalinaHome() {        if (System.getProperty(Globals.CATALINA_HOME_PROP) != null)            return;        File bootstrapJar =            new File(System.getProperty("user.dir"), "bootstrap.jar");        if (bootstrapJar.exists()) {            try {                System.setProperty                    (Globals.CATALINA_HOME_PROP,                     (new File(System.getProperty("user.dir"), ".."))                     .getCanonicalPath());            } catch (Exception e) {                // Ignore                System.setProperty(Globals.CATALINA_HOME_PROP,                                   System.getProperty("user.dir"));            }        } else {            System.setProperty(Globals.CATALINA_HOME_PROP,                               System.getProperty("user.dir"));        }    }

??? 通过上面的代码可以看出,它设置的catalina.home的值,就是获取系统user.dir属性的值,也就是你当前eclipse导入tomcat源码建的项目的路径,如果你项目路径如下所示:tomcat7源码学习札记(启动篇)

?????? 它的location在E:\study\tomcat7下面,那么System.getProperty("user.dir")的值也是E:\study\tomcat7.因为我们导入的源码中不会有bootstrap.jar,所以它在E:\study\tomcat7\bootstrap.jar是不存在的,最后setCatalinaHome()这个方法执行的代码是:

else {            System.setProperty(Globals.CATALINA_HOME_PROP,                               System.getProperty("user.dir"));        }

?????? 也就是将catalina.home的值设置成为:E:\study\tomcat7。对于setCatalinaBase()的源码类似,就不再贴出,分析。

?

?????? 3.2? 初始化作为catalina的加载类

????? 对于这个功能,我们可以参看initClassLoaders()这个方法的源码:

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) {            handleThrowable(t);            log.error("Class loader creation threw exception", t);            System.exit(1);        }    }

? ? ? ? 通过源码,在这个方法中我们看不到实质的内容,它们主要都是通过createClassLoader(String name, ClassLoader parent)这个方法来创建三个类型(commonLoader、catalinaLoader、sharedLoader)的加载类的。那我们就通过源码来看下这个方法的功能:

private ClassLoader createClassLoader(String name, ClassLoader parent)        throws Exception {        String value = CatalinaProperties.getProperty(name + ".loader");        if ((value == null) || (value.equals("")))            return parent;        value = replace(value);        List<Repository> repositories = new ArrayList<Repository>();        StringTokenizer tokenizer = new StringTokenizer(value, ",");        while (tokenizer.hasMoreElements()) {            String repository = tokenizer.nextToken().trim();            if (repository.length() == 0) {                continue;            }            // Check for a JAR URL repository            try {                @SuppressWarnings("unused")                URL url = new URL(repository);                repositories.add(                        new Repository(repository, RepositoryType.URL));                continue;            } catch (MalformedURLException e) {                // Ignore            }            // Local repository            if (repository.endsWith("*.jar")) {                repository = repository.substring                    (0, repository.length() - "*.jar".length());                repositories.add(                        new Repository(repository, RepositoryType.GLOB));            } else if (repository.endsWith(".jar")) {                repositories.add(                        new Repository(repository, RepositoryType.JAR));            } else {                repositories.add(                        new Repository(repository, RepositoryType.DIR));            }        }        ClassLoader classLoader = ClassLoaderFactory.createClassLoader            (repositories, parent);        // Retrieving MBean server        MBeanServer mBeanServer = null;        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {            mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);        } else {            mBeanServer = ManagementFactory.getPlatformMBeanServer();        }        // Register the server classloader        ObjectName objectName =            new ObjectName("Catalina:type=ServerClassLoader,name=" + name);        mBeanServer.registerMBean(classLoader, objectName);        return classLoader;    }

???? ?? 通过源码可以看出,这个方法主要是两个功能:首先,通过CatalinaProperties这个类,来获取相应要加载进来的jar包,然后通过调用replace(),来定位到相应的jar包,也就是把jar包的路径解析出来。然后,通过jmx将这些jar包的组件注册到tomcat中来;

??????? 对于这个方法中用到的CatalinaProperties,这个类主要是读取catalina配置的,这个类首先会执行静态块中的loadProperties()方法

/**     * Load properties.     */    private static void loadProperties() {        InputStream is = null;        Throwable error = null;        try {            String configUrl = getConfigUrl();            if (configUrl != null) {                is = (new URL(configUrl)).openStream();            }        } catch (Throwable t) {            handleThrowable(t);        }        if (is == null) {            try {                File home = new File(getCatalinaBase());                File conf = new File(home, "conf");                File propsFile = new File(conf, "catalina.properties");                is = new FileInputStream(propsFile);            } catch (Throwable t) {                handleThrowable(t);            }        }        if (is == null) {            try {                is = CatalinaProperties.class.getResourceAsStream                    ("/org/apache/catalina/startup/catalina.properties");            } catch (Throwable t) {                handleThrowable(t);            }        }        if (is != null) {            try {                properties = new Properties();                properties.load(is);                is.close();            } catch (Throwable t) {                handleThrowable(t);                error = t;            }        }        if ((is == null) || (error != null)) {            // Do something            log.warn("Failed to load catalina.properties", error);            // That's fine - we have reasonable defaults.            properties=new Properties();        }        // Register the properties as system properties        Enumeration<?> enumeration = properties.propertyNames();        while (enumeration.hasMoreElements()) {            String name = (String) enumeration.nextElement();            String value = properties.getProperty(name);            if (value != null) {                System.setProperty(name, value);            }        }    }

?????? 因为,这时还没有设置catalina.config系统属性,所以String configUrl = getConfigUrl();获取不到值,代码会接着执行:

File home = new File(getCatalinaBase()); File conf = new File(home, "conf"); File propsFile = new File(conf, "catalina.properties"); is = new FileInputStream(propsFile);

???? 通过这可以看出是读取conf/catalina.properties这个属性配置文件,然后通过下面代码加载到属性文件中

 if (is != null) {            try {                properties = new Properties();                properties.load(is);                is.close();            } catch (Throwable t) {                handleThrowable(t);                error = t;            }        }

????? 所以,通过以上的代码可以看出CatalinaProperties这个类最终读取的是conf/catalina.properties配置文件,这样在Bootstrap.java这个类中的createClassLoader(String name, ClassLoader parent)方法的第一句

String value = CatalinaProperties.getProperty(name + ".loader");

????? 读取的值就是conf/catalina.properties里面配置的值。这个方法后面的代码就是对于加载进行来conf/catalina.properties配置中的server.loader、common.loader、shared.loader三个值中的组件的注册工作。到些初始化catalina类的加载类分析工作已经完成,那接着看初始catalina。

?

???? 3.3 初始化catalina

????? 初始化catalina类的代码主要是Bootstrap.java类中init()方法后面的代码:

 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;

?? ? ?? 首先通过前面已经初始化好的catalina的加载类,也就是org.apache.catalina.loader.StandardClassLoader来加载org.apache.catalina.startup.Catalina这个类,然后设置org.apache.catalina.startup.Catalina类的parentClassLoader为org.apache.catalina.loader.StandardClassLoader(这其中用到反射机制)。

?

?????? 通过以上的简单讲解,让大家大致了解到tomcat在启动时做的部分工作。

???

热点排行