Tomcat详解 四

作者: 李东龙

原文地址: http://www.iteye.com/topic/584116

 

    之前有写过关于tomcat中常用的一些类结构的文章。

    解析Tomcat之HttpServlet(截图记录)

    今天来关注一下,tomcat的类加载器相关的内容。

  PS: 由于前一篇文章内容比较简单, 有朋友冠以我标题党之嫌,对于此种说法,本人深感抱歉,可能标题确实有点大,但是这些常用的类,我更多的时候只关注其用法,而忽略了内部实现,所以也就把这些内容总结了一下,发了出来。别无标题党之意,请各位eyer海涵。

 

  OK, 现在进入正题. Tomcat类加载器初始化.

  开始之前,我们首先需要了解一下几个基本的知识点;

 

1.tomcat中类加载器的结构与关系。

   这里,我引用tomcat文档的一个简图来说明一下, 有兴趣深究的朋友,可以去翻看tomcat的文档,理解更多信息.

  


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(tomcat5.5)

 (由于参考的是tomcat6.0的源代码,这里纠正一下类加载器的图(如下),以免给别的朋友造成误解,同时也多谢asialee给出的提醒

 
(tomcat6.0)
 

2.每种类加载器分别加载什么资源: 

     这些内容,可以在tomcat文档的  Class Loader HOW-TO 找到.

    这里我要说明的是, 在tomcat中,这些内容是记录在哪里的。既(程序怎么让tomcat知道,需要加载哪些类)

    答案是-----

     其通过一个配置文件来指定的:(catalina.properties),这个文件默认存放在

     tomcat路径下的 bin/bootstrap.jar中。

    如图

    

 

   
    打开文件,其内容如下:

 

Java代码 复制代码  收藏代码
  1. # Licensed to the Apache Software Foundation (ASF) under one or more   
  2. # contributor license agreements.  See the NOTICE file distributed with   
  3. this work for additional information regarding copyright ownership.   
  4. # The ASF licenses this file to You under the Apache License, Version 2.0  
  5. # (the "License"); you may not use this file except in compliance with   
  6. # the License.  You may obtain a copy of the License at   
  7. #   
  8. #     http://www.apache.org/licenses/LICENSE-2.0   
  9. #   
  10. # Unless required by applicable law or agreed to in writing, software   
  11. # distributed under the License is distributed on an "AS IS" BASIS,   
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   
  13. # See the License for the specific language governing permissions and   
  14. # limitations under the License.   
  15.   
  16. #   
  17. # List of comma-separated packages that start with or equal this string   
  18. # will cause a security exception to be thrown when   
  19. # passed to checkPackageAccess unless the   
  20. # corresponding RuntimePermission ("accessClassInPackage."+package) has   
  21. # been granted.   
  22. package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.   
  23. #   
  24. # List of comma-separated packages that start with or equal this string   
  25. # will cause a security exception to be thrown when   
  26. # passed to checkPackageDefinition unless the   
  27. # corresponding RuntimePermission ("defineClassInPackage."+package) has   
  28. # been granted.   
  29. #   
  30. # by default, no packages are restricted for definition, and none of   
  31. # the class loaders supplied with the JDK call checkPackageDefinition.   
  32. #   
  33. package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.   
  34.   
  35. #   
  36. #   
  37. # List of comma-separated paths defining the contents of the "common"    
  38. # classloader. Prefixes should be used to define what is the repository type.   
  39. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.   
  40. # If left as blank,the JVM system loader will be used as Catalina's "common"    
  41. # loader.   
  42. # Examples:   
  43. #     "foo": Add this folder as a class repository   
  44. #     "foo/*.jar": Add all the JARs of the specified folder as class    
  45. #                  repositories   
  46. #     "foo/bar.jar": Add bar.jar as a class repository   
  47. common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar   
  48.   
  49. #   
  50. # List of comma-separated paths defining the contents of the "server"    
  51. # classloader. Prefixes should be used to define what is the repository type.   
  52. # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.   
  53. # If left as blank, the "common" loader will be used as Catalina's "server"    
  54. # loader.   
  55. # Examples:   
  56. #     "foo": Add this folder as a class repository   
  57. #     "foo/*.jar": Add all the JARs of the specified folder as class    
  58. #                  repositories   
  59. #     "foo/bar.jar": Add bar.jar as a class repository   
  60. server.loader=   
  61.   
  62. #   
  63. # List of comma-separated paths defining the contents of the "shared"    
  64. # classloader. Prefixes should be used to define what is the repository type.   
  65. # Path may be relative to the CATALINA_BASE path or absolute. If left as blank,   
  66. # the "common" loader will be used as Catalina's "shared" loader.   
  67. # Examples:   
  68. #     "foo": Add this folder as a class repository   
  69. #     "foo/*.jar": Add all the JARs of the specified folder as class    
  70. #                  repositories   
  71. #     "foo/bar.jar": Add bar.jar as a class repository    
  72. # Please note that for single jars, e.g. bar.jar, you need the URL form   
  73. # starting with file:.   
  74. shared.loader=   
  75.   
  76. #   
  77. # String cache configuration.   
  78. tomcat.util.buf.StringCache.byte.enabled=true  
  79. #tomcat.util.buf.StringCache.char.enabled=true  
  80. #tomcat.util.buf.StringCache.trainThreshold=500000  
  81. #tomcat.util.buf.StringCache.cacheSize=5000  
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans.
#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
# passed to checkPackageDefinition unless the
# corresponding RuntimePermission ("defineClassInPackage."+package) has
# been granted.
#
# by default, no packages are restricted for definition, and none of
# the class loaders supplied with the JDK call checkPackageDefinition.
#
package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.

#
#
# List of comma-separated paths defining the contents of the "common" 
# classloader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
# If left as blank,the JVM system loader will be used as Catalina's "common" 
# loader.
# Examples:
#     "foo": Add this folder as a class repository
#     "foo/*.jar": Add all the JARs of the specified folder as class 
#                  repositories
#     "foo/bar.jar": Add bar.jar as a class repository
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar

#
# List of comma-separated paths defining the contents of the "server" 
# classloader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute.
# If left as blank, the "common" loader will be used as Catalina's "server" 
# loader.
# Examples:
#     "foo": Add this folder as a class repository
#     "foo/*.jar": Add all the JARs of the specified folder as class 
#                  repositories
#     "foo/bar.jar": Add bar.jar as a class repository
server.loader=

#
# List of comma-separated paths defining the contents of the "shared" 
# classloader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
# the "common" loader will be used as Catalina's "shared" loader.
# Examples:
#     "foo": Add this folder as a class repository
#     "foo/*.jar": Add all the JARs of the specified folder as class 
#                  repositories
#     "foo/bar.jar": Add bar.jar as a class repository 
# Please note that for single jars, e.g. bar.jar, you need the URL form
# starting with file:.
shared.loader=

#
# String cache configuration.
tomcat.util.buf.StringCache.byte.enabled=true
#tomcat.util.buf.StringCache.char.enabled=true
#tomcat.util.buf.StringCache.trainThreshold=500000
#tomcat.util.buf.StringCache.cacheSize=5000

 

 

 此文件,下面会有详细的介绍.

 

 

OK,到此,我们初步了解到tomcat关于类加载器的一些知识。 下面来详细看看,tomcat内部是怎么来初始化这些类加载器的吧.

 

 首先, 我们知道, java程序都需要一个入口(main方法), 而在tomcat中,这个入口在

  org.apache.catalina.startup.Bootstrap 这个类中。

  看其结构:

 


    定位到方法内部:

    

Java代码 复制代码  收藏代码
  1. public static void main(String args[]) {   
  2.   
  3.         if (daemon == null) {   
  4.             daemon = new Bootstrap();   
  5.             try {   
  6.                 //初始化资源   (今天来了解的.)   
  7.                 daemon.init();   
  8.             } catch (Throwable t) {   
  9.                 t.printStackTrace();   
  10.                 return;   
  11.             }   
  12.         }   
  13.            
  14.         try {   
  15.             //默认为启动   
  16.             String command = "start";   
  17.             if (args.length > 0) {   
  18.                 command = args[args.length - 1];   
  19.             }   
  20.                
  21.             if (command.equals("startd")) {   
  22.                 args[args.length - 1] = "start";   
  23.                 daemon.load(args);   
  24.                 daemon.start();   
  25.             } else if (command.equals("stopd")) {   
  26.                 args[args.length - 1] = "stop";   
  27.                 daemon.stop();   
  28.             } else if (command.equals("start")) {   
  29.                 //设置标识   
  30.                 daemon.setAwait(true);   
  31.                 daemon.load(args);   
  32.                 //开启   
  33.                 daemon.start();   
  34.             } else if (command.equals("stop")) {   
  35.                 daemon.stopServer(args);   
  36.             } else {   
  37.                 log.warn("Bootstrap: command \"" + command + "\" does not exist.");   
  38.             }   
  39.         } catch (Throwable t) {   
  40.             t.printStackTrace();   
  41.         }   
  42.     }  
public static void main(String args[]) {

        if (daemon == null) {
            daemon = new Bootstrap();
            try {
            	//初始化资源   (今天来了解的.)
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }
        
        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 {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

 

  在tomcat启动之前, 需要初始化一些系统资源, 初始化的详细工作都定义在init()方法内部了。

 

    OK,我们继续追踪一下。 定位到init()方法中.\

 

 

Java代码 复制代码  收藏代码
  1. public void init()   
  2.     throws Exception   
  3. {   
  4.     // Set Catalina path 设置catalina基本路径   
  5.     setCatalinaHome();   
  6.     setCatalinaBase();   
  7.        
  8.     //初始化类加载器   
  9.     initClassLoaders();   
  10.        
  11.     Thread.currentThread().setContextClassLoader(catalinaLoader);   
  12.     SecurityClassLoad.securityClassLoad(catalinaLoader);   
  13.     // Load our startup class and call its process() method   
  14.     if (log.isDebugEnabled())   
  15.         log.debug("Loading startup class");   
  16.     Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");   
  17.     Object startupInstance = startupClass.newInstance();   
  18.     // Set the shared extensions class loader   
  19.     if (log.isDebugEnabled())   
  20.         log.debug("Setting startup class properties");   
  21.     String methodName = "setParentClassLoader";   
  22.     Class paramTypes[] = new Class[1];   
  23.     paramTypes[0] = Class.forName("java.lang.ClassLoader");   
  24.     Object paramValues[] = new Object[1];   
  25.     paramValues[0] = sharedLoader;   
  26.     Method method =startupInstance.getClass().getMethod(methodName, paramTypes);   
  27.     method.invoke(startupInstance, paramValues);   
  28.     catalinaDaemon = startupInstance;   
  29. }  
    public void init()
        throws Exception
    {
        // Set Catalina path 设置catalina基本路径
        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;
    }

 

  可以看到, 上面的代码中,用来初始化类加载器、验证类加载器、

  以及使用类加载器来加载类"org.apache.catalina.startup.Catalina"等等操作。

  这篇文章,主要来探讨一下,tomcat初始化类加载器的方式, ,所以,我们追踪到方法initClassLoaders()中:

  

   这里主要介绍一下,下面的流程, tomcat会调用initClassLoaders()方法。

   用来初始化common ,catalina,shared三种类加载器,而这个操作是通过方法

   createClassLoader(String name, ClassLoader parent)来完成的。

   而后2个都属于common的子级,

   所以下面给出2个方法的源代码(其中相关信息,都以注释给出):

  

 

Java代码 复制代码  收藏代码
  1. /**  
  2.     * 初始化类加载器:  
  3.     * 加载三种:  
  4.     *        common.  
  5.     *        /           \  
  6.     *  catalina   shared.   
  7.     */  
  8.    private void initClassLoaders() {   
  9.        try {   
  10.         //创建common类加载器   
  11.            commonLoader = createClassLoader("common"null);   
  12.            if( commonLoader == null ) {   
  13.                // no config file, default to this loader - we might be in a 'single' env.   
  14.                commonLoader=this.getClass().getClassLoader();   
  15.            }   
  16.            //创建catalina类加载器,指定其父级别的加载器为commonLoader.   
  17.            catalinaLoader = createClassLoader("server", commonLoader);   
  18.            //创建sharedLoader类加载器,指定其父级别的加载器为commonLoader.   
  19.            sharedLoader = createClassLoader("shared", commonLoader);   
  20.        } catch (Throwable t) {   
  21.            log.error("Class loader creation threw exception", t);   
  22.            System.exit(1);   
  23.        }   
  24.    }  
 /**
     * 初始化类加载器:
     * 加载三种:
     *        common.
     *        /           \
     *  catalina   shared. 
     */
    private void initClassLoaders() {
        try {
        	//创建common类加载器
            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();
            }
            //创建catalina类加载器,指定其父级别的加载器为commonLoader.
            catalinaLoader = createClassLoader("server", commonLoader);
            //创建sharedLoader类加载器,指定其父级别的加载器为commonLoader.
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

   

  

Java代码 复制代码  收藏代码
  1. /**  
  2.      * 创建类加载器  
  3.      *   
  4.      * @param name  
  5.      * @param parent 指定上一级别的类加载器  
  6.      * @return  
  7.      * @throws Exception  
  8.      */  
  9.     private ClassLoader createClassLoader(String name, ClassLoader parent)   
  10.         throws Exception {   
  11.         //这里以common为例: 从catalina.properties中获取common.loader  类加载信息    
  12.         //如:   
  13.         //common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar   
  14.         String value = CatalinaProperties.getProperty(name + ".loader");   
  15.         // 如果没有任何信息,则返回父加载器   
  16.         if ((value == null) || (value.equals("")))   
  17.             return parent;   
  18.            
  19.         ArrayList repositoryLocations = new ArrayList();   
  20.         ArrayList repositoryTypes = new ArrayList();   
  21.         int i;   
  22.         //以逗号分隔.   
  23.         StringTokenizer tokenizer = new StringTokenizer(value, ",");   
  24.            
  25.         while (tokenizer.hasMoreElements()) {   
  26.             String repository = tokenizer.nextToken();   
  27.             // Local repository   
  28.             boolean replace = false;   
  29.             String before = repository;   
  30.             //是否含有"${catalina.home}"   
  31.             while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {   
  32.                 replace=true;   
  33.                 if (i>0) {   
  34.                     //替换成tomcat路径  替换后的形式如下: c:/opensource/tomcat5/lib.   
  35.                 repository = repository.substring(0,i) + getCatalinaHome()    
  36.                     + repository.substring(i+CATALINA_HOME_TOKEN.length());   
  37.                 } else {   
  38.                     repository = getCatalinaHome()    
  39.                         + repository.substring(CATALINA_HOME_TOKEN.length());   
  40.                 }   
  41.             }   
  42.             //是否含有"${catalina.base}"   
  43.             while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {   
  44.                 replace=true;   
  45.                 if (i>0) {   
  46.                     //同上,替换    
  47.                 repository = repository.substring(0,i) + getCatalinaBase()    
  48.                     + repository.substring(i+CATALINA_BASE_TOKEN.length());   
  49.                 } else {   
  50.                     repository = getCatalinaBase()    
  51.                         + repository.substring(CATALINA_BASE_TOKEN.length());   
  52.                 }   
  53.             }   
  54.             if (replace && log.isDebugEnabled())   
  55.                 log.debug("Expanded " + before + " to " + repository);   
  56.   
  57.             // Check for a JAR URL repository   
  58.             try {   
  59.                 URL url=new URL(repository);   
  60.                 repositoryLocations.add(repository);   
  61.                 repositoryTypes.add(ClassLoaderFactory.IS_URL);   
  62.                 continue;   
  63.             } catch (MalformedURLException e) {   
  64.                 // Ignore   
  65.             }   
  66.                
  67.                
  68.             if (repository.endsWith("*.jar")) {   
  69.                 repository = repository.substring   
  70.                     (0, repository.length() - "*.jar".length());   
  71.                 repositoryLocations.add(repository);   
  72.                 repositoryTypes.add(ClassLoaderFactory.IS_GLOB);   
  73.             } else if (repository.endsWith(".jar")) {   
  74.                 repositoryLocations.add(repository);   
  75.                 repositoryTypes.add(ClassLoaderFactory.IS_JAR);   
  76.             } else {   
  77.                 repositoryLocations.add(repository);   
  78.                 repositoryTypes.add(ClassLoaderFactory.IS_DIR);   
  79.             }   
  80.         }   
  81.            
  82.            
  83.            
  84.         String[] locations = (String[]) repositoryLocations.toArray(new String[0]);   
  85.         Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);   
  86.            
  87.         //创建类加载器   
  88.         ClassLoader classLoader = ClassLoaderFactory.createClassLoader   
  89.             (locations, types, parent);   
  90.   
  91.         // Retrieving MBean server   
  92.         MBeanServer mBeanServer = null;   
  93.         if (MBeanServerFactory.findMBeanServer(null).size() > 0) {   
  94.             mBeanServer =   
  95.                 (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);   
  96.         } else {   
  97.             mBeanServer = ManagementFactory.getPlatformMBeanServer();   
  98.         }   
  99.   
  100.         // Register the server classloader   
  101.         ObjectName objectName =   
  102.             new ObjectName("Catalina:type=ServerClassLoader,name=" + name);   
  103.         mBeanServer.registerMBean(classLoader, objectName);   
  104.         return classLoader;   
  105.     }  
/**
     * 创建类加载器
     * 
     * @param name
     * @param parent 指定上一级别的类加载器
     * @return
     * @throws Exception
     */
    private ClassLoader createClassLoader(String name, ClassLoader parent)
        throws Exception {
    	//这里以common为例: 从catalina.properties中获取common.loader  类加载信息 
    	//如:
    	//common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar
        String value = CatalinaProperties.getProperty(name + ".loader");
        // 如果没有任何信息,则返回父加载器
        if ((value == null) || (value.equals("")))
            return parent;
        
        ArrayList repositoryLocations = new ArrayList();
        ArrayList repositoryTypes = new ArrayList();
        int i;
        //以逗号分隔.
        StringTokenizer tokenizer = new StringTokenizer(value, ",");
        
        while (tokenizer.hasMoreElements()) {
            String repository = tokenizer.nextToken();
            // Local repository
            boolean replace = false;
            String before = repository;
            //是否含有"${catalina.home}"
            while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
                replace=true;
                if (i>0) {
                	//替换成tomcat路径  替换后的形式如下: c:/opensource/tomcat5/lib.
                repository = repository.substring(0,i) + getCatalinaHome() 
                    + repository.substring(i+CATALINA_HOME_TOKEN.length());
                } else {
                    repository = getCatalinaHome() 
                        + repository.substring(CATALINA_HOME_TOKEN.length());
                }
            }
            //是否含有"${catalina.base}"
            while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
                replace=true;
                if (i>0) {
                	//同上,替换 
                repository = repository.substring(0,i) + getCatalinaBase() 
                    + repository.substring(i+CATALINA_BASE_TOKEN.length());
                } else {
                    repository = getCatalinaBase() 
                        + repository.substring(CATALINA_BASE_TOKEN.length());
                }
            }
            if (replace && log.isDebugEnabled())
                log.debug("Expanded " + before + " to " + repository);

            // Check for a JAR URL repository
            try {
                URL url=new URL(repository);
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_URL);
                continue;
            } catch (MalformedURLException e) {
                // Ignore
            }
            
            
            if (repository.endsWith("*.jar")) {
                repository = repository.substring
                    (0, repository.length() - "*.jar".length());
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
            } else if (repository.endsWith(".jar")) {
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_JAR);
            } else {
                repositoryLocations.add(repository);
                repositoryTypes.add(ClassLoaderFactory.IS_DIR);
            }
        }
        
        
        
        String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
        Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
        
        //创建类加载器
        ClassLoader classLoader = ClassLoaderFactory.createClassLoader
            (locations, types, parent);

        // Retrieving MBean server
        MBeanServer mBeanServer = null;
        if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
            mBeanServer =
                (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;
    }

 

 

  到这里,我们可以确定,tomcat文档中的类加载器之间关系是准确的,并非凭空说的。 

    到这里,我们可能对于createClassLoader()方法的

Java代码 复制代码  收藏代码
  1. CatalinaProperties.getProperty(name + ".loader");  
CatalinaProperties.getProperty(name + ".loader");

  有点疑问, 到底tomcat是如果通过配置文件来获取需要初始化类加载器的相关信息的呢/

 

 前面我们看到 catalina.properties中记录了tomcat三种类加载器中分别需要加载一些什么类的信息。

  而CatalinaProperties类正是用来解析此文件的,以告诉tomcat,哪种类加载器,加载哪些类。

 

  我们来看看这个类的源代码:

 

Java代码 复制代码  收藏代码
  1. /**  
  2.  * Utility class to read the bootstrap Catalina configuration.  
  3.  * 读取tomcat 的配置文件 catalina.properties  
  4.  * @author Remy Maucherat  
  5.  * @version $Revision: 467222 $ $Date: 2006-10-24 11:17:11 +0800 (星期二, 24 十月 2006) $  
  6.  */  
  7.   
  8. public class CatalinaProperties {   
  9.     // ------------------------------------------------------- Static Variables   
  10.     private static org.apache.juli.logging.Log log=   
  11.         org.apache.juli.logging.LogFactory.getLog( CatalinaProperties.class );   
  12.     private static Properties properties = null;   
  13.   
  14.     static {   
  15.         loadProperties();   
  16.     }   
  17.   
  18.   
  19.     // --------------------------------------------------------- Public Methods   
  20.   
  21.   
  22.     /**  
  23.      * Return specified property value.  
  24.      */  
  25.     public static String getProperty(String name) {   
  26.         return properties.getProperty(name);   
  27.     }   
  28.   
  29.   
  30.     /**  
  31.      * Return specified property value.  
  32.      */  
  33.     public static String getProperty(String name, String defaultValue) {   
  34.         return properties.getProperty(name, defaultValue);   
  35.     }   
  36.   
  37.   
  38.     // --------------------------------------------------------- Public Methods   
  39.   
  40.   
  41.     /**  
  42.      * 加载配置信息  
  43.      * Load properties.  
  44.      */  
  45.     private static void loadProperties() {   
  46.         InputStream is = null;   
  47.         Throwable error = null;   
  48.         //第一步: 从系统变量中查找   
  49.         try {   
  50.             //getConfigUrl()方法的内容为:   System.getProperty("catalina.config");   
  51.             String configUrl = getConfigUrl();   
  52.             if (configUrl != null) {   
  53.                 is = (new URL(configUrl)).openStream();   
  54.             }   
  55.         } catch (Throwable t) {   
  56.             // Ignore   
  57.         }   
  58.   
  59.         //第二步:再从tomcat的conf目录下去找   
  60.         if (is == null) {   
  61.             try {   
  62.                 File home = new File(getCatalinaBase());   
  63.                 File conf = new File(home, "conf");   
  64.                 File properties = new File(conf, "catalina.properties");   
  65.                 is = new FileInputStream(properties);   
  66.             } catch (Throwable t) {   
  67.                 // Ignore   
  68.             }   
  69.         }   
  70.            
  71.         //还没找到: 则从类路径中加载.   
  72.         if (is == null) {   
  73.             try {   
  74.                 is = CatalinaProperties.class.getResourceAsStream   
  75.                     ("/org/apache/catalina/startup/catalina.properties");   
  76.             } catch (Throwable t) {   
  77.                 // Ignore   
  78.             }   
  79.         }   
  80.            
  81.         // 到这里的话,如果找到了,就将配置文件中加载过来   
  82.         if (is != null) {   
  83.             try {   
  84.                 properties = new Properties();   
  85.                 properties.load(is);   
  86.                 is.close();   
  87.             } catch (Throwable t) {   
  88.                 error = t;   
  89.             }   
  90.         }   
  91.   
  92.         if ((is == null) || (error != null)) {   
  93.             // Do something   
  94.             log.warn("Failed to load catalina.properties", error);   
  95.             // That's fine - we have reasonable defaults.   
  96.             properties=new Properties();   
  97.         }   
  98.            
  99.         //将配置文件的key-value 设置为 系统变量.   
  100.         // Register the properties as system properties   
  101.         Enumeration enumeration = properties.propertyNames();   
  102.         while (enumeration.hasMoreElements()) {   
  103.             String name = (String) enumeration.nextElement();   
  104.             String value = properties.getProperty(name);   
  105.             if (value != null) {   
  106.                 System.setProperty(name, value);   
  107.             }   
  108.         }   
  109.   
  110.     }   
  111.   
  112.   
  113.     /**  
  114.      * Get the value of the catalina.home environment variable.  
  115.      */  
  116.     private static String getCatalinaHome() {   
  117.         return System.getProperty("catalina.home",   
  118.                                   System.getProperty("user.dir"));   
  119.     }   
  120.        
  121.        
  122.     /**  
  123.      * Get the value of the catalina.base environment variable.  
  124.      */  
  125.     private static String getCatalinaBase() {   
  126.         return System.getProperty("catalina.base", getCatalinaHome());   
  127.     }   
  128.   
  129.   
  130.     /**  
  131.      * Get the value of the configuration URL.  
  132.      */  
  133.     private static String getConfigUrl() {   
  134.         return System.getProperty("catalina.config");   
  135.     }   
  136.   
  137.   
  138. }  
/**
 * Utility class to read the bootstrap Catalina configuration.
 * 读取tomcat 的配置文件 catalina.properties
 * @author Remy Maucherat
 * @version $Revision: 467222 $ $Date: 2006-10-24 11:17:11 +0800 (星期二, 24 十月 2006) $
 */

public class CatalinaProperties {
    // ------------------------------------------------------- Static Variables
    private static org.apache.juli.logging.Log log=
        org.apache.juli.logging.LogFactory.getLog( CatalinaProperties.class );
    private static Properties properties = null;

    static {
        loadProperties();
    }


    // --------------------------------------------------------- Public Methods


    /**
     * Return specified property value.
     */
    public static String getProperty(String name) {
        return properties.getProperty(name);
    }


    /**
     * Return specified property value.
     */
    public static String getProperty(String name, String defaultValue) {
        return properties.getProperty(name, defaultValue);
    }


    // --------------------------------------------------------- Public Methods


    /**
     * 加载配置信息
     * Load properties.
     */
    private static void loadProperties() {
        InputStream is = null;
        Throwable error = null;
        //第一步: 从系统变量中查找
        try {
        	//getConfigUrl()方法的内容为:   System.getProperty("catalina.config");
            String configUrl = getConfigUrl();
            if (configUrl != null) {
                is = (new URL(configUrl)).openStream();
            }
        } catch (Throwable t) {
            // Ignore
        }

        //第二步:再从tomcat的conf目录下去找
        if (is == null) {
            try {
                File home = new File(getCatalinaBase());
                File conf = new File(home, "conf");
                File properties = new File(conf, "catalina.properties");
                is = new FileInputStream(properties);
            } catch (Throwable t) {
                // Ignore
            }
        }
        
        //还没找到: 则从类路径中加载.
        if (is == null) {
            try {
                is = CatalinaProperties.class.getResourceAsStream
                    ("/org/apache/catalina/startup/catalina.properties");
            } catch (Throwable t) {
                // Ignore
            }
        }
        
        // 到这里的话,如果找到了,就将配置文件中加载过来
        if (is != null) {
            try {
                properties = new Properties();
                properties.load(is);
                is.close();
            } catch (Throwable 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();
        }
        
        //将配置文件的key-value 设置为 系统变量.
        // 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);
            }
        }

    }


    /**
     * Get the value of the catalina.home environment variable.
     */
    private static String getCatalinaHome() {
        return System.getProperty("catalina.home",
                                  System.getProperty("user.dir"));
    }
    
    
    /**
     * Get the value of the catalina.base environment variable.
     */
    private static String getCatalinaBase() {
        return System.getProperty("catalina.base", getCatalinaHome());
    }


    /**
     * Get the value of the configuration URL.
     */
    private static String getConfigUrl() {
        return System.getProperty("catalina.config");
    }


}

 

 OK, 到此,tomcat初始化类加载器的过程,我们都已经了解了。

 可能看到这里,有的人觉得还是不太理解。 好,让我们来总结一下,这个顺序。

   我们按照我们平时常用的操作来看;

  1.我要启动tomcat .. (调用Bootstrap的main  方法)

      (1)tomcat启动之前,需要加载类,需要类加载器。 于是,它去做初始化工作. -----> init()方法.

      (2)init()方法开始工作它再去调用------>initClassLoaders()方法.

      (3)发现需要初始化3个类型的类加载器,再调用---> createClassLoader(name,parent) ,告诉它,我要初始化哪种类型的,它的老爸是谁。

      (4)通过CatalinaProperties 类去联络catalina.properties,获得,这个哪种类加载器加载哪些类的信息。

      (5) 完成初始化,并返回.

  2.tomcat 加载其他资源(待续),启动成功……

  

 OK, 文章写完了, 这些内容都是本人自己学习的记录,难免有错误之处,还望大家多提意见,希望能跟各位javaeyer共同交流,达到共同提高的目录。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值