`

Tomcat&&ClassLoader

阅读更多

1 - Tomcat的类载入器的结构

Tomcat Server在启动的时候将构造一个ClassLoader树,以保证模块的类库是私有的
Tomcat Server的ClassLoader结构如下:
其中:
- Bootstrap - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar
- System - 载入$CLASSPATH/*.class
- Common - 载入$CATALINA_HOME/common/...,它们对TOMCAT和所有的WEB APP都可见
- Catalina - 载入$CATALINA_HOME/server/...,它们仅对TOMCAT可见,对所有的WEB APP都不可见
- Shared - 载入$CATALINA_HOME/shared/...,它们仅对所有WEB APP可见,对TOMCAT不可见(也不必见)
- WebApp? - 载入ContextBase?/WEB-INF/...,它们仅对该WEB APP可见

 

2 - ClassLoader的工作原理

每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类
系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类
可以使用Thread.currentThread().setContextClassLoader(...);更改当前线程的contextClassLoader,来改变其载入类的行为

ClassLoader被组织成树形,一般的工作原理是:
1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类
2) contextClassLoader请求它的父ClassLoader来完成该载入请求
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入

注意:WebApp?ClassLoader的工作原理和上述有少许不同:
它先试图自己载入类(在ContextBase?/WEB-INF/...中载入类),如果无法载入,再请求父ClassLoader完成

由此可得:
- 对于WEB APP线程,它的contextClassLoader是WebApp?ClassLoader
- 对于Tomcat Server线程,它的contextClassLoader是CatalinaClassLoader

3 - 部分原代码分析

3.1 - org/apache/catalina/startup/Bootstrap.java

Tomcat Server线程的起点
构造ClassLoader树,并设置Tomcat Server线程的contextClassLoader为catalinaloader
载入若干类,然后转入org.apache.catalina.startup.Catalina类中

---------------------------------------
package org.apache.catalina.startup;

// JDK类库
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

// apache自己的类库
import org.apache.catalina.loader.Extension;
import org.apache.catalina.loader.StandardClassLoader;

/**
 * Boostrap loader for Catalina.     This application constructs a class loader
 * for use in loading the Catalina internal classes (by accumulating all of the
 * JAR files found in the "server" directory under "catalina.home"), and
 * starts the regular execution of the container.     The purpose of this
 * roundabout approach is to keep the Catalina internal classes (and any
 * other classes they depend on, such as an XML parser) out of the system
 * class path and therefore not visible to application level classes.
 *
 * @author Craig R. McClanahan
 * @version $Revision: 1.36 $ $Date: 2002/04/01 19:51:31 $
 */

/**
 * 该类的main方法的主要任务:
 * --------------------------
 *
 * 1,创建TOMCAT自己的类载入器(ClassLoader)
 *         +---------------------------+
 *         |            Bootstrap            |
 *         |                |                |
 *         |             System              |
 *         |                |                |
 *         |             Common              |
 *         |            /         \             |
 *         |        Catalina     Shared         |
 *         +---------------------------+
 *       其中:
 *       - Bootstrap - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar
 *       - System       - 载入$CLASSPATH/*.class
 *       - Common       - 载入$CATALINA_HOME/common/...,它们对TOMCAT和所有的WEB APP都可见
 *       - Catalina     - 载入$CATALINA_HOME/server/...,它们仅对TOMCAT可见,对所有的WEB APP都不可见
 *       - Shared       - 载入$CATALINA_HOME/shared/...,它们仅对所有WEB APP可见,对TOMCAT不可见(也不必见)
 *       注意:当一个ClassLoader被请求载入一个类时,它首先请求其父ClassLoader完成载入,
 *       仅当其父ClassLoader无法载入该类时,才试图自己载入该类
 * 2,改变本身线程的默认ClassLoader(本线程就是Tomcat Server线程,类载入器是catalinaLoader)
 * 3,让catalinaLoader载入一些类,类的位置在$CATALINA_HOME/server/lib/catalina.jar中
 * 4,创建org.apache.catalina.startup.Catalina类的一个实例startupInstance,并为其调用方法:
 *       startupInstance.setParentClassLoader(sharedLoader);
 *       startupInstance.process(args);
 *
 *
 * 有关ClassLoader的说明:
 * -----------------------
 *
 * 每个被DEPLOY的WEB APP都会被创建一个ClassLoader,用来载入该WEB APP自己的类
 * 这些类的位置是webappX/WEB-INF/classes/*.class和webappX/WEB-INF/lib/*.jar
 *
 * ClassLoader的工作流程是:
 * 1) 收到一个载入类的的请求
 * 2) 请求其父ClassLoader来完成该类的载入
 * 3) 如果父ClassLoader无法载入,则自己试图完成该类的载入
 *
 * 特别注意WEB APP自己的ClassLoader的实现与众不同:
 * 它先试图从WEB APP自己的目录里载入,如果失败则请求父ClassLoader的代理
 * 这样可以让不同的WEB APP之间的类载入互不干扰
 *
 * WEB APP的ClassLoader的层次结构是:
 *        +----------------------------+
 *        |          Shared                  |
 *        |         /         \ ...             |
 *        |      Webapp1     Webapp2     ...       |
 *        +----------------------------+
 * 故对于一个WEB APP,其类载入的优先顺序如下:
 * - /WEB-INF/classes/*.class 和 /WEB-INF/lib/*.jar
 * - Bootstrap classes of JVM
 * - System class loader classes
 * - $CATALINA_HOME/common/...
 * - $CATALINA_HOME/shared/...
 *
 *
 * 小结:
 * ------
 *
 * 综上分析
 * - Tomcat Server线程使用的classLoader是Catalina
 * - 每个WEB APP线程使用的classloader是Webapp?
 *
 */

public final class Bootstrap {

       /**
        * DEBUG级别
        */
       private static int debug = 0;

       /**
        * 脚本执行该程序时,提供以下的系统属性:
        * java.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
        * java.security.manager \
        * java.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
        * catalina.base="$CATALINA_BASE" \
        * catalina.home="$CATALINA_HOME" \
        * java.io.tmpdir="$CATALINA_TMPDIR" \
        *
        * @param args Command line arguments to be processed
        */
       public static void main(String args[]) {

           // 设置debug
           for (int i = 0; i < args.length; i++)     {
               if ("-debug".equals(args[i]))
                   debug = 1;
           }

           // 设置好系统属性catalina.base,即保证其有值
           if (System.getProperty("catalina.base") == null)
               System.setProperty("catalina.base", getCatalinaHome());

           // 创建三个ClassLoader
           // 这三个对象是通过ClassLoaderFactory的静态方法创建的
           // 其实际类型是StandardClassLoader,完成tomcat自定义的类载入
           // 这些类对非tomcat及其上的webapp的其它java程序不可见,故用自己的Classloader载入
           ClassLoader commonLoader = null;
           ClassLoader catalinaLoader = null;
           ClassLoader sharedLoader = null;
           try {

               File unpacked[] = new File[1];
               File packed[] = new File[1];
               File packed2[] = new File[2];
               
               ClassLoaderFactory.setDebug(debug);

               // $CATALINA_HOME/common/classes/*.class - 未压缩的类
               // $CATALINA_HOME/common/endorsed/*.jar - 压缩的类(endorse:支持)
               // $CATALINA_HOME/common/lib/*.jar - 压缩的类
               // 这些类是被tomcat server以及所有的webapp所共享的类,由commonLoader负责载入
               unpacked[0] = new File(getCatalinaHome(),
                                      "common" + File.separator + "classes");
               packed2[0] = new File(getCatalinaHome(),
                                     "common" + File.separator + "endorsed");
               packed2[1] = new File(getCatalinaHome(),
                                     "common" + File.separator + "lib");
               commonLoader =
                   ClassLoaderFactory.createClassLoader(unpacked, packed2, null);

               // $CATALINA_HOME/server/classes/*.class
               // $CATALINA_HOME/server/lib/*.jar
               // 这些类是仅被tomcat server使用而对webapp不可见的类,由catalinaLoader负责载入
               unpacked[0] = new File(getCatalinaHome(),
                                      "server" + File.separator + "classes");
               packed[0] = new File(getCatalinaHome(),
                                    "server" + File.separator + "lib");
               catalinaLoader =
                   ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                        commonLoader);

               // $CATALINA_BASE/shared/classes/*.class
               // $CATALINA_BASE/shared/lib/*.jar
               // 这些类是仅被tomcat的webapp使用的类,由sharedLoader负责载入
               unpacked[0] = new File(getCatalinaBase(),
                                      "shared" + File.separator + "classes");
               packed[0] = new File(getCatalinaBase(),
                                    "shared" + File.separator + "lib");
               sharedLoader =
                   ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                        commonLoader);
                                                        
               // 注意三个自己定置的ClassLoader的层次关系:
               // systemClassLoader (root)
               //      +--- commonLoader
               //             +--- catalinaLoader
               //             +--- sharedLoader
           } catch (Throwable t) {
               log("Class loader creation threw exception", t);
               System.exit(1);

           }

           // 为当前的线程更改其contextClassLoader
           // 一般的线程默认的contextClassLoader是系统的ClassLoader(所有其它自定义ClassLoader的父亲)
           // 当该线程需要载入类时,将使用自己的contextClassLoader来寻找并载入类
           // 更改contextClassLoader可以更改该线程的寻找和载入类的行为,但不影响到其它线程
           // 注意!Tomcat Server线程使用的是catalinaLoader
           Thread.currentThread().setContextClassLoader(catalinaLoader);

           // Load our startup class and call its process() method
           try {

               // 预载入catalinalLoader的一些类
               SecurityClassLoad.securityClassLoad(catalinaLoader);

               // 获得tomcat的启动类:org.apache.catalina.startup.Catalina,并创建该类的一个实例
               if (debug >= 1)
                   log("Loading startup class");
               Class startupClass =
                   catalinaLoader.loadClass
                   ("org.apache.catalina.startup.Catalina");
               Object startupInstance = startupClass.newInstance();

               // 设置startupInstance的父ClassLoader,相当于执行:
               // Catalina startupInstance = new Catailina();
               // startupInstance.setParentClassLoader(sharedLoader);
               // 详情参考类org.apache.catalina.startup.Catalina
               if (debug >= 1)
                   log("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);

               // 使用main方法获得的参数args来执行process方法,相当于:
               // startupInstance.process(args);
               // 详情参考类org.apache.catalina.startup.Catalina
               if (debug >= 1)
                   log("Calling startup class process() method");
               methodName = "process";
               paramTypes = new Class[1];
               paramTypes[0] = args.getClass();
               paramValues = new Object[1];
               paramValues[0] = args;
               method =
                   startupInstance.getClass().getMethod(methodName, paramTypes);
               method.invoke(startupInstance, paramValues);

           } catch (Exception e) {
               System.out.println("Exception during startup processing");
               e.printStackTrace(System.out);
               System.exit(2);
           }

       }

       /**
        * 返回$CATALINA_HOME变量。如果该变量没有定义,则将之赋值为用户的当前工作目录。
        */
       private static String getCatalinaHome() {
           return System.getProperty("catalina.home",
                                     System.getProperty("user.dir"));
       }

       /**
        * 返回$CATALINA_BASE变量。如果该变量没有定义,则将之赋值为$CATALINA_HOME。
        */
       private static String getCatalinaBase() {
           return System.getProperty("catalina.base", getCatalinaHome());
       }

       /**
        * 输出LOG信息。
        */
       private static void log(String message) {

           System.out.print("Bootstrap: ");
           System.out.println(message);

       }

       /**
        * 输出由异常引起的LOG信息。
        */
       private static void log(String message, Throwable exception) {

           log(message);
           exception.printStackTrace(System.out);

       }

}
--------------------------------------------------------

 

 

           +-----------------------------+
           |            Bootstrap              |
           |                |                  |
           |             System                |
           |                |                  |
           |             Common                |
           |            /         \               |
           |        Catalina     Shared           |
           |                  /       \           |
           |             WebApp1     WebApp2      |
           +-----------------------------+
分享到:
评论

相关推荐

    Tomcat 5.0.18 ClassLoader source code insight

    《深入解析Tomcat 5.0.18 ClassLoader源码》 在Java Web开发中,Tomcat作为一款广泛使用的应用服务器,其内部机制对于开发者来说具有极高的学习价值。尤其是Tomcat的ClassLoader机制,它是Java类加载的核心部分,...

    Tomcat研究之ClassLoader.pdf

    ### Tomcat中的ClassLoader详解 #### 一、引言 在深入了解Tomcat的工作原理时,一个重要的组成部分就是其ClassLoader机制。本文旨在深入剖析Tomcat中特有的类加载器(ClassLoader)体系结构,帮助读者理解Tomcat...

    tomcat 类加载机制 —— ClassLoader

    《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于理解和优化应用性能至关重要。本文将深入探讨Tomcat的ClassLoader是如何工作的,以及它如何影响到...

    Tomcat加载顺序

    ### Tomcat加载顺序详解 Apache Tomcat作为一款广泛使用的开源Servlet容器,其类加载机制是理解和维护基于Tomcat的应用程序的重要部分。Tomcat的类加载器遵循特定的加载顺序,确保了不同应用间的隔离性和资源的正确...

    Tomcat中JNDI原理

    当`myApp`启动时,Tomcat会自动创建与`myApp`对应的ClassLoader,并通过`ContextBindings`将`jdbc/myDataSource`与该ClassLoader绑定。然后,在应用中,可以使用以下代码来获取数据源: ```java Context initCtx = ...

    《深入剖析 Tomcat》PDF版本下载.txt

    2. **Catalina ClassLoader**加载Tomcat核心类库; 3. **Common ClassLoader**加载Tomcat公共类库; 4. **WebApp ClassLoader**加载Web应用类库; 5. **Connector**和**Container**等组件初始化; 6. **Web应用**...

    Tomcat:apache-tomcat-6.0.18

    5. **ClassLoader机制**:Tomcat使用自定义的ClassLoader来加载Web应用程序的类,确保不同应用之间的类隔离,防止冲突。 Tomcat 6.0.18版的特性包括: 1. **性能优化**:相对于之前的版本,6.0.18进行了性能调优,...

    tomcat类加载器

    4. Common ClassLoader:在Tomcat中,它是所有Web应用共享的类加载器,用于加载`common.loader`配置项指定的类路径。 5. WebApp ClassLoader:每个Web应用有自己的类加载器,它加载应用的`WEB-INF/classes`和`WEB-...

    tomcat 学习与分析总结资料

    主要有三个类加载器:Bootstrap ClassLoader、Common ClassLoader和Webapp ClassLoader。Bootstrap加载JDK的类,Common加载`common.loader`指定的类,而Webapp类加载器则负责加载每个Web应用自己的类。理解类加载...

    java类加载器-tomcat中的类加载器

    4. 最后,如果所有父类加载器都未能加载,Catalina ClassLoader才加载Tomcat自身的类。 VSD文件可能包含一个流程图,详细描绘了Tomcat类加载器的工作流程和关系,这对于理解类加载机制非常有帮助。通过阅读和分析该...

    Tomcat启动顺序

    Bootstrap类加载器完成后,Tomcat会使用系统类加载器(System ClassLoader)加载服务器的全局配置文件,如`server.xml`。这个文件定义了Tomcat的整体架构,包括服务(Service)、连接器(Connector)和引擎(Engine)等组件...

    tomcat-8.0.50.zip

    5. **ClassLoader**:Tomcat使用自定义的ClassLoader来加载Web应用程序的类,这使得不同的应用程序可以使用相同的库而不会相互冲突。 6. **部署与管理**:可以通过修改conf/server.xml和conf/context.xml文件,或者...

    深入剖析Tomcat 随书 源码

    《深入剖析Tomcat》这本书是Java开发者们探索Tomcat服务器内部机制的重要参考资料,它带领读者逐步揭开Tomcat的神秘面纱,深入理解其工作原理。Tomcat作为一款轻量级的开源Web应用服务器,广泛应用于各种Java Web...

Global site tag (gtag.js) - Google Analytics