`

Tomcat 源代码分析之ClassLoader

阅读更多

 

Tomcat 源代码分析之ClassLoader

此系列文章皆为Tomcat 7.0代码代码分析。

 

1. ClassLoader基础知识

1.1. Parent-Child委托模型

 

我们知道Java系统中,类加载器的默认加载方式是采用Parent-Child委托方式加载类的,即就是说,先尝试使用父类加载器加载类,如果没有找到,才自己加载该类,可以看到,这是一个递归的加载过程,核心代码大致如下:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class c = findLoadedClass(name);
            if (c == null) {
                ……
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    …
                    c = findClass(name);
                    ……
                }
            }
            ……
            return c;
        }
    }
 很多ClassLoader的继承类都默认了这种加载方式,其中用途比较广泛的有URLClassLoader。

1.2. 类加载器运行时模型:

 

当一个JVM启动时,至少有三个ClassLoader会被启动:

1. Bootstrap 类加载器

加载Java核心包,它们被置放在(<JAVA_HOME>/lib目录下,这部分是JVM的一部分,往往使用native code完成

2. Extensions类加载器

加载Java扩展包,即位于<JAVA_HOME>/lib/ext下的包,这里要注意的是,有些JVM的这个加载器和Bootstrap类加载器是同一个加载器,而Sun是把二者分开的,其实现类为sun.misc.Launcher$ExtClassLoader。

3. System类加载器

这个类加载器加载CLASSPATH下的类,Sun的 默认实现是sun.misc.Launcher$ExtClassLoader。

这三者之间的父子关系是:Bootstrap类加载器是Extensions类加载器的父类加载器,而Extensions类加载器是System类加载器的父类加载器。

2. Tomcat Classloader模型

Tomcat 7.0的ClassLoader加载层次模型如下图所示:

 

 

这个模型和之前Tomcat 5.5之前有些不同,因为之前的除过Common类加载器之外,还有Catalina类加载器和Shared类加载器,这个只能导致更多的配置和概念,已经不再使用了,虽然还可以进行配置。

1. Common类加载器:加载$CATALINA_HOME/lib和$CATALINA_BASE/lib下的class文件和jar包以及旗下的资源文件,这些文件将会被所有Web应用共有,也会被Tomcat运行时用到。其配置在catalina.properties下,如果没有配置,则默认使用System类加载器,配置示例:
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar
2. App类加载器:Web 应用的类加载器,Web应用下的资源文件,class文件盒jar包,按照Java Web规范的标准,它们位于Web应用的/WEB-INF/classes和/WEB-INF/lib文件夹下。

3. 类加载器的实现

 

Tomcat类加载器其实有三个类实现:StandardClassLoader,WebappClassLoader和JasperLoader,这三个类加载器都是URLClassLoader的子类。不同的是,StandardClassLoader并没有客户化URLClassLoader方法,即,它也是采用委托的方式加载类的。而其他都覆写了loadClass()方法。

1. StandardClassLoader类加载器会创建Common类加载器的实例。

2. WebappClassLoader为每个应用创建类加载器实例,对于加载Web应用的类时,我们并非推荐使用父子委托模型,但是必须保证以java.*和javax.*开头的包必须由System类加载器加载,即最终由Bootstrap加载器加载。

核心代码如下:

public Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException {

       ……

        // (0) Check our previously loaded local class cache
        clazz = findLoadedClass0(name);
        if (clazz != null) {
            if (log.isDebugEnabled())
                log.debug("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.1) Check our previously loaded class cache
        clazz = findLoadedClass(name);
        if (clazz != null) {
            if (log.isDebugEnabled())
                log.debug("  Returning class from cache");
            if (resolve)
                resolveClass(clazz);
            return (clazz);
        }

        // (0.2) Try loading the class with the system class loader, to prevent
        //       the webapp from overriding J2SE classes
       //保证以java.*和javax.*开头的包必须由System类加载器加载
        try {
            clazz = system.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        ……

        boolean delegateLoad = delegate || filter(name);

        // (1) Delegate to our parent if requested
        //Mbeans加载时,是否采用delegate方式
        if (delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader1 " + parent);
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        // (2) Search local repositories
       //先本地加载,不委托父加载器加载
        if (log.isDebugEnabled())
            log.debug("  Searching local repositories");
        try {
            clazz = findClass(name);
            if (clazz != null) {
                if (log.isDebugEnabled())
                    log.debug("  Loading class from local repository");
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            ;
        }

        // 最后使用父加载器加载
        if (!delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader at end: " + parent);
            ClassLoader loader = parent;
            if (loader == null)
                loader = system;
            try {
                clazz = loader.loadClass(name);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                ;
            }
        }

        throw new ClassNotFoundException(name);
    }

可以看到,并非简单的父子委托方式加载类

3. JasperLoader是为了加载jsp编译成的servlet而创建的类加载器,它覆写了loadClass()方法,除过加载org.apache.jsp.*的文件外,其他的均使用父加载器加载。

核心代码如下:

public Class loadClass(final String name, boolean resolve)
        throws ClassNotFoundException {

        Class clazz = null;                
                                           
        // (0) Check our previously loaded class cache
        clazz = findLoadedClass(name);     
        if (clazz != null) {               
            if (resolve)                   
                resolveClass(clazz);       
            return (clazz);        
        }                          
                          
        // (.5) Permission to access this class when using a SecurityManager
        ……

	if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) {
            // Class is not in org.apache.jsp, therefore, have our
            // parent load it
            clazz = parent.loadClass(name);            
	    if( resolve )
		resolveClass(clazz);
	    return clazz;
	}
        //所有的以org.apache.jsp.*开头的文件都由该类加载器加载。
	return findClass(name);
    }
 

 

今天就讲到这里了。

 

 

  • 大小: 10.9 KB
分享到:
评论
2 楼 superysy 2012-06-13  
看得云里雾里的
1 楼 c929833623 2012-02-17  
分析得不错,继续关注

相关推荐

    TOMCAT源代码,包括转载得别人的分析

    它的源代码是公开的,这使得开发者能够深入理解其内部工作原理,优化性能,或者为它添加自定义功能。以下是对Tomcat源码及其分析的一些关键知识点: 1. **Servlet与JSP**: Tomcat的核心在于Servlet容器,它负责...

    tomcat 类加载机制 —— ClassLoader

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

    Tomcat源代码学习研究

    《深入剖析Tomcat源代码:探索底层实现原理》 Tomcat作为开源的Java Servlet容器,是许多Web开发者和系统管理员的首选。它以其轻量级、高效和稳定性著称,而深入理解其源代码,有助于我们更好地优化应用性能,解决...

    Tomcat 5.0.18 ClassLoader source code insight

    在分析Tomcat ClassLoader源码时,我们还可以关注到`findClass()`方法,它是`loadClass()`的补充,负责从本地类路径加载类。此外,`resolveClass()`方法则用于将二进制字节码转换为`java.lang.Class`对象。 总的来...

    tomcat源码学习

    【标签】"源码"和"tomcat8"提示我们,我们将关注的是Tomcat 8版本的源代码。Tomcat 8是一个重要的版本,引入了Java EE 7的支持,包括WebSocket API等新特性。源码分析可以帮助开发者理解这些特性的实现细节,以及...

    Tomcat6的源码

    【标题】"Tomcat6的源码"涵盖了Java Web服务器Apache Tomcat的第六个主要版本的源代码。这个版本在2005年发布,它为开发者提供了深入了解Servlet和JSP容器工作原理的机会,同时也支持Java EE 5规范。Tomcat6是开源...

    tomcat8源码的maven项目

    【标题】:“Tomcat8源码的Maven项目”是一个基于Maven构建的Apache Tomcat 8服务器的源代码分析项目。Apache Tomcat是一个开源的Java Servlet容器,它实现了Java EE Web应用程序规范,如Servlet、JSP和EL...

    tomcat 6 源码

    在这个压缩包中,你将找到Apache Tomcat 6.0.32版本的完整源代码。 首先,我们来探讨Tomcat的核心组件: 1. **Catalina**:这是Tomcat的主要组件,负责处理Servlet和JSP的请求。Catalina包含一系列的类,如`org....

    apache-tomcat-7.0.81-src 源码免费下载

    在"apache-tomcat-7.0.81-src"这个压缩包中,你将获得Tomcat 7.0.81版本的完整源代码,这包括了服务器的所有核心组件和模块。通过分析这些源码,我们可以学习到以下关键知识点: 1. **Servlet容器**:Tomcat作为...

    tomcat8源码

    Tomcat8作为Maven工程,遵循了Maven的标准目录结构,包括`src/main/java`(源代码)、`src/main/resources`(资源文件)、`src/test/java`(测试代码)等。通过Maven,开发者可以方便地管理依赖,构建和部署项目。 ...

    apache-tomcat-源码-lib包

    通过分析和学习Apache Tomcat的源码,开发者可以更好地理解Web服务器的工作原理,提高问题定位和性能优化的能力。同时,这也是深入学习Java Web技术的重要途径,有助于提升开发者在Web应用开发和服务器管理方面的...

    Tomcat7 源码Eclipse工程

    通过阅读这些模块的源代码,我们可以了解到Tomcat如何接收并处理HTTP请求,如何加载和执行Servlet,以及JSP如何被转换成Servlet并执行。 对于`server.xml`,它是Tomcat的核心配置文件,定义了服务器的监听端口、...

    深入剖析Tomcat 随书 源码

    总的来说,《深入剖析Tomcat源码》这本书将带领我们探索Tomcat的每一个角落,从基础架构到高级特性,全面解析其设计思想和实现细节,帮助开发者更好地理解和优化自己的Java Web应用。通过学习和研究Tomcat源码,我们...

    Tomcat:apache-tomcat-6.0.18

    在压缩包"apache-tomcat-6.0.18-src"中,包含了Tomcat源代码,这对于开发者来说非常有价值。通过源代码,我们可以深入理解Tomcat的工作原理,进行定制化开发或调试。源码包含了以下几个主要部分: 1. **Catalina**:...

Global site tag (gtag.js) - Google Analytics