`
p2p2500
  • 浏览: 11387 次
  • 性别: Icon_minigender_2
  • 来自: 南京
社区版块
存档分类
最新评论

Tomcat类加载机制

 
阅读更多

Tomcat类加载机制

1. 概述

Tomcat内置了一系列的类加载器,保证运行在容器中的不同Web应用程序使用不同的类路径和资源仓库。在Java环境中,类加载机制采用双亲委派机制;但是,在Tomcat中WebappClassLoader加载器并未采用这种机制(在后面将详细讨论)。 随着Tomcat版本的不断变化,Tomcat5,Tomcat6和Tomcat7,8在类加载的过程中存在一些不同之处,在后面章节将逐一讨论。

2. Tomcat中的类加载器

Tomcat中自定义的类加载器有4种,分别是Common,Catalina,Shared 和WebApp,具体定义如下:

名称 实现类 父加载器 ClassPath
Common org.apache.catalina.loader.StandardClassLoader system /common/*
Catalina 同上 common /server/*
Shared 同上 common /shared/*
WebApp org.apache.catalina.loader.WebappClassLoader shared /WebApp/WEB-INF/*

 

详细的关系如下图(pic2-1):

Classloader parent-child relationships 5

3. 类加载器初始化过程

Tomcat启动后首先启动初始化:Common,Catalina和Shared类加载器。具体调用如下:
org.apache.catalina.startup.Bootstrap#main

org.apache.catalina.startup.Bootstrap#init

org.apache.catalina.startup.Bootstrap#initClassLoaders

 

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类加载器
            catalinaLoader = createClassLoader("server", commonLoader);
            // Shared类加载器
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }
 

 

org.apache.catalina.startup.Bootstrap#createClassLoader代码如下:

 

private ClassLoader createClassLoader(String name, ClassLoader parent)
        throws Exception {
        // 根据${Tomcat_home}\conf\catalina.properties获取属性值
        String value = CatalinaProperties.getProperty(name + ".loader");
        if ((value == null) || (value.equals("")))
            return parent;
-中略-
 

 

4. Tomcat各个版本类加载器区别

Tomcat5.5

Tomcat5的中默认catalina.properties属性文件如下:

common.loader=${catalina.home}/common/classes,${catalina.home}/common/i18n/*.jar,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar
shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar

因此,Tomcat5 会分别创建:Common,Catalina和Shared类加载器,相应关系如(pic2-1) Classloader parent-child relationships 5

Tomcat6.x or later

默认catalina.properties属性文件如下:

common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
server.loader=
shared.loader=

因此,他们创建的Common,Catalina和Shared类加载器为同一个实例,即Common,相应的关系图如下(pic4-1)

Classloader parent-child relationships 6 or later

5. Tomcat的类加载机制

Tomcat 的类加载器实现类有两种:StandardClassLoader和WebappClassLoader两种。其中StandardClassLoader未重载loadClass方法,因此采用的仍然是双亲委派原则;然而WebappClassLoader重载了loadClass方法,使用了另外一种类加载策略。然而,各个版本又有稍许差别。

Tomcat6

当delegate="false"时,默认值
  1. 检查缓存中是否存在要加载的类
  2. 若缓存中没有,则首先使用系统类加载器加载,防止Web应用程序中的类覆盖J2SE的类
  3. 从当前仓库中载入相关类
  4. 使用父类载入器。若父类载入器为null,使用系统的类加载器进行加载
  5. 若仍未找到需要的类,则抛出ClasNotFoundException异常。
    类加载顺序:

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • $CATALINA_HOME/common/classes
  • $CATALINA_HOME/common/endorsed/*.jar
  • $CATALINA_HOME/common/i18n/*.jar
  • $CATALINA_HOME/common/lib/*.jar
  • $CATALINA_BASE/shared/classes
  • $CATALINA_BASE/shared/lib/*.jar
当delegate="true"时
  1. 检查缓存中是否存在要加载的类
  2. 若缓存中没有,则首先使用系统类加载器加载,防止Web应用程序中的类覆盖J2SE的类
  3. 使用父类载入器。若父类载入器为null,使用系统的类加载器进行加载
  4. 从当前仓库中载入相关类
  5. 若仍未找到需要的类,则抛出ClasNotFoundException异常。
    类加载顺序:

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • $CATALINA_HOME/common/classes
  • $CATALINA_HOME/common/endorsed/*.jar
  • $CATALINA_HOME/common/i18n/*.jar
  • $CATALINA_HOME/common/lib/*.jar
  • $CATALINA_BASE/shared/classes
  • $CATALINA_BASE/shared/lib/*.jar
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application

备注:默认情况下,Tomcat6 shared类加载器路径。

org.apache.catalina.loader.WebappClassLoader#loadClass

 

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

        if (log.isDebugEnabled())
            log.debug("loadClass(" + name + ", " + resolve + ")");
        Class clazz = null;

        // Log access to stopped classloader
        if (!started) {
            try {
                throw new IllegalStateException();
            } catch (IllegalStateException e) {
                log.info(sm.getString("webappClassLoader.stopped", name), e);
            }
        }

        // (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
        try {
            // 使用系统类加载器
            clazz = system.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        // (0.5) Permission to access this class when using a SecurityManager
        if (securityManager != null) {
            int i = name.lastIndexOf('.');
            if (i >= 0) {
                try {
                    securityManager.checkPackageAccess(name.substring(0,i));
                } catch (SecurityException se) {
                    String error = "Security Violation, attempt to use " +
                        "Restricted Class: " + name;
                    log.info(error, se);
                    throw new ClassNotFoundException(error, se);
                }
            }
        }

        boolean delegateLoad = delegate || filter(name);

        // (1) Delegate to our parent if requested
        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) {
            ;
        }

        // (3) Delegate to parent unconditionally
        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);

    }
 

 

Tomcat7 or later

当delegate="false"时,默认值
  1. 检查缓存中是否存在要加载的类
  2. 若缓存中没有,则首先使用引导类加载器加载,防止Web应用程序中的类覆盖J2SE的类
  3. 从当前仓库中载入相关类
  4. 使用父类载入器。若父类载入器为null,使用引导类加载器进行加载
  5. 若仍未找到需要的类,则抛出ClasNotFoundException异常。

类加载顺序:

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)
当delegate="true"时
  1. 检查缓存中是否存在要加载的类
  2. 若缓存中没有,则首先使用引导类加载器加载,防止Web应用程序中的类覆盖J2SE的类
  3. 使用父类载入器。若父类载入器为null,使用引导类加载器进行加载
  4. 从当前仓库中载入相关类
  5. 若仍未找到需要的类,则抛出ClasNotFoundException异常。
    类加载顺序:

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • Common class loader classes (described above)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application

org.apache.catalina.loader.WebappClassLoader#loadClass

 

    public synchronized Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException {

        if (log.isDebugEnabled())
            log.debug("loadClass(" + name + ", " + resolve + ")");
        Class<?> clazz = null;

        // Log access to stopped classloader
        if (!started) {
            try {
                throw new IllegalStateException();
            } catch (IllegalStateException e) {
                log.info(sm.getString("webappClassLoader.stopped", name), e);
            }
        }

        // (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
        try {
            // j2seClassLoader为引导类加载器。
            clazz = j2seClassLoader.loadClass(name);
            if (clazz != null) {
                if (resolve)
                    resolveClass(clazz);
                return (clazz);
            }
        } catch (ClassNotFoundException e) {
            // Ignore
        }

        // (0.5) Permission to access this class when using a SecurityManager
        if (securityManager != null) {
            int i = name.lastIndexOf('.');
            if (i >= 0) {
                try {
                    securityManager.checkPackageAccess(name.substring(0,i));
                } catch (SecurityException se) {
                    String error = "Security Violation, attempt to use " +
                        "Restricted Class: " + name;
                    log.info(error, se);
                    throw new ClassNotFoundException(error, se);
                }
            }
        }

        boolean delegateLoad = delegate || filter(name);

        // (1) Delegate to our parent if requested
        if (delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader1 " + parent);
            try {
                clazz = Class.forName(name, false, parent);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
        }

        // (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) {
            // Ignore
        }

        // (3) Delegate to parent unconditionally
        if (!delegateLoad) {
            if (log.isDebugEnabled())
                log.debug("  Delegating to parent classloader at end: " + parent);
            try {
                clazz = Class.forName(name, false, parent);
                if (clazz != null) {
                    if (log.isDebugEnabled())
                        log.debug("  Loading class from parent");
                    if (resolve)
                        resolveClass(clazz);
                    return (clazz);
                }
            } catch (ClassNotFoundException e) {
                // Ignore
            }
        }

        throw new ClassNotFoundException(name);

    }
 

 

j2seClassLoader类的初始化

 

public WebappClassLoader() {
-中略-
        ClassLoader j = String.class.getClassLoader();
        if (j == null) {
            j = getSystemClassLoader();
            while (j.getParent() != null) {
                j = j.getParent();
            }
        }
        this.j2seClassLoader = j;
-中略-
}
 

 

参考链接

[1].Tomcat5.5 Class Loader HOW-TO
[2].Tomcat6.0 Class Loader HOW-TO
[3].Tomcat7.0 Class Loader HOW-TO
[4].Tomcat8.0 Class Loader HOW-TO
[5].Tomcat download

以上。

分享到:
评论

相关推荐

    tomcat 类加载机制 —— ClassLoader

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

    tomcat类加载器

    在Tomcat中,类加载机制的设计是为了支持多个Web应用程序的隔离运行。每个Web应用都有自己的类加载器,这样可以确保一个应用的类不会意外地与另一个应用的类混淆。默认的类加载器结构包括以下层次: 1. Bootstrap ...

    tomcat 源码分析系列文档

    5. "tomcat加载类的顺序.doc":详细说明了Tomcat加载类的具体步骤和顺序,这对于理解和调试类加载问题至关重要。 6. "Tomcat源码研究.pdf":提供了一个全面的源码分析概览,可能包括了Tomcat的主要组件、设计模式...

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

    Tomcat,作为广泛使用的Java Servlet容器,它自定义了一套类加载机制,以满足Web应用程序的特殊需求。下面我们将深入探讨Java类加载器以及Tomcat中的类加载器。 在Java中,类加载器主要分为三个层次:Bootstrap ...

    tomcat使用与调优,nginx

    第五部分:Tomcat 类加载机制剖析 第六部分:Tomcat 对 Https 的⽀持及 Tomcat 性能优化策略 nginx 第⼀部分:Nginx基础回顾(Nginx是什么?能做什么事情(应⽤在什么场合)?常⽤命令是什么?) 第⼆部分:Nginx核⼼...

    Tomcat组成及工作原理借鉴.pdf

    Tomcat 的类加载机制是基于 Java 的类加载机制。它使用了多个类加载器来加载不同的类和资源。这些类加载器包括: * Bootstrap:加载 Java 的核心类库 * System:加载系统类库 * Common:加载 Tomcat 的公共类库 * ...

    Tomcat启动时类加载顺序

    #### 二、类加载机制概述 在Java中,类加载器(ClassLoader)负责将.class文件加载到JVM中。Tomcat通过自定义的类加载器实现了特定的类加载顺序,以确保能够正确处理不同来源的类文件,避免类的重复加载和类版本冲突...

    tomcat调优.zip

    【标题】"Tomcat调优.zip"所包含的是一系列关于Tomcat服务器优化的资料,主要探讨了Tomcat的整体架构、线程模型以及类加载机制等核心知识点。 首先,我们来深入理解一下Tomcat的整体架构及其设计精髓。Tomcat作为一...

    Java 类在 Tomcat 中是如何加载的(过程分析)

    当Tomcat加载类时,它遵循以下顺序: - 使用Bootstrap类加载器尝试加载。 - 使用System类加载器尝试加载。 - 使用Webapp类加载器加载`WEB-INF/classes`下的类。 - 使用Webapp类加载器加载`WEB-INF/lib`中的jar...

    Tomcat工作原理祥解

    总结,Tomcat的工作原理涉及类加载机制、配置文件解析以及请求处理流程等复杂环节。理解这些原理对于优化Tomcat性能、解决故障和开发高效Web应用至关重要。深入学习Tomcat,可以提高开发效率并更好地管理服务器资源...

    Tomcat 配置分解

    ### Tomcat配置详解 #### Tomcat简介 Tomcat是一个开源的轻量级Web应用程序服务器,在中小型...此外,掌握Tomcat的类加载机制有助于开发者更好地理解Web应用在Tomcat中的运行方式,从而更有效地进行开发和维护工作。

    让tomcat自动加载修改过的类和servlet

    因此,让Tomcat自动加载修改过的类和Servlet成为提高开发效率的关键需求之一。 ### 让Tomcat自动加载修改过的类和Servlet #### 知识点一:理解Tomcat的热部署机制 Tomcat默认情况下并不会自动检测到类或Servlet的...

    Tomcat通俗讲解

    Tomcat采用了多层类加载机制,确保不同层次的应用之间不会出现类加载冲突。以下是类加载器的基本层级结构及其加载顺序: - **Bootstrap ClassLoader**:加载Java核心类库,位于`$JAVA_HOME/jre/lib/ext/*.jar`。 - ...

    面试必问之jvm与性能优化.docx

    本文将深入探讨JVM加载Class文件的机制,类加载器的概念及其类型,以及Tomcat服务器特有的类加载机制。 1. JVM加载Class文件的原理机制 JVM加载Class文件的过程分为三个主要阶段:装载、连接和初始化。 - **装载*...

    携程Java高级工程师岗位面试真题

    以上内容是Java高级工程师面试中常见的知识点,包括JVM加载Class的原理、类加载器的角色以及Tomcat的类加载机制。理解这些内容对于深入理解Java应用程序的运行机制以及解决相关问题至关重要。在面试中,展示对这些...

    Tomcat详解

    Tomcat采用了一种层次化的类加载机制,确保每个类加载器只加载自己权限范围内的类,并遵循特定的加载顺序。这种机制保证了系统的稳定性和安全性。 1. **Bootstrap**:加载核心Java库,这些库通常位于`$JAVA_HOME/...

    类加载器与Tomcat

    在Java的运行环境中,类加载器扮演着至关重要...在处理类冲突、版本控制和热部署等问题时,理解Tomcat的类加载机制至关重要。开发者在进行应用部署和配置时,必须考虑到类加载器的层次和行为,以避免潜在的问题和冲突。

    译 Java类加载机制(二)

    例如,在大型企业级应用和容器(如Tomcat)中,类加载机制的理解和利用是优化系统性能和维护性的关键。 总的来说,Java类加载机制是一个复杂但重要的主题,涉及到类加载器、类的生命周期、双亲委派模型以及自定义...

    2021Java大厂面试题——大厂真题之携程-Java高级.pdf

    在Tomcat服务器中,类的加载方式与JVM的标准类加载机制有所不同。Tomcat采用了更加细粒度的类加载策略,以支持更复杂的Web应用程序部署。 **1. Tomcat中的类加载器** 当Tomcat启动时,会创建几种类加载器: - **...

Global site tag (gtag.js) - Google Analytics