一文讲透 Tomcat 的类加载机制!揭秘类加载核心

沙海 2021年5月7日06:26:11Java评论142字数 3208阅读10分41秒阅读模式
摘要

速读摘要

速读摘要文章源自JAVA秀-https://www.javaxiu.com/22499.html

这些类加载器的工作原理是一样的,区别是它们的加载路径不同,也就是说findClass这个方法查找的路径不同。重新部署,此时该Web应用的类加载器将会重新创建,而且不会影响其他Web应用。Web应用包含的Jar包,性能自然高于应用服务器只有一个类加载器的情况。/到这里还是没有加载上再次尝试使用父类加载器进行加载if(!在37行英文注释中标注获取的是系统类加载器,但我们debug的时候会发现他是扩展类加载器,实际中我们可以推断出他应该是扩展类加载器,因为如果我们加载的类在扩展类加载器路径下已经存在的话,那我们直接调用系统类加载器是就是错误的了,下图为debug后获取的类加载器的验证。文章源自JAVA秀-https://www.javaxiu.com/22499.html

原文约 2352 | 图片 6 | 建议阅读 5 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心

三太子敖丙 文章源自JAVA秀-https://www.javaxiu.com/22499.html

以下文章来源于架构之美,作者马坤鹏 / 孙玄文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

架构之美文章源自JAVA秀-https://www.javaxiu.com/22499.html

设计满足业务的系统架构、大数据中台、算法平台,并非易事。在这里分享一线大厂线上真实案例的思考和实践,让我们在互联网架构设计、大数据研发、机器学习实践之路上共同成长!文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

-     前言     -文章源自JAVA秀-https://www.javaxiu.com/22499.html

你了解 Apache Tomcat 的类加载机制吗?本文将从底层原理切入,彻底揭秘 Tomcat 类加载所涉及的源码、机制和方案,助你深入掌握 Tomcat 类加载核心!文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

-     JVM 类加载器     -文章源自JAVA秀-https://www.javaxiu.com/22499.html

1、JVM类加载器文章源自JAVA秀-https://www.javaxiu.com/22499.html

说起 Tomcat 类加载器,就不得不先简单说一下 JVM 类加载器,如下图所示:文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 启动类加载器:Bootstrap ClassLoader,用于加载JVM提供的基础运行类,即位于%JAVA_HOME%/jre/lib目录下的核 心类库;文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 扩展类加载器:Extension ClassLoader, Java提供的一个标准的扩展机制用于加载除核心类库外的Jar包,即只要复制 到指定的扩展目录(可以多个)下的Jar, JVM会自动加载(不需要通过-classpath指定)。默认的扩展目录是%JAVA_HOME%加e/lib/ext。典型的应用场景就是,Java使用该类加载 器加载JVM默认提供的但是不属于核心类库的Jar。不推荐将应用程序依赖的 类库放置到扩展目录下,因为该目录下的类库对所有基于该JVM运行的应用程序可见;文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 应用程序类加载器:Application ClassLoader ,用于加载环境变量CLASSPATH (不推荐使用)指定目录下的或者-classpath运行 参数指定的Jar包。System类加载器通常用于加载应用程序Jar包及其启动入口类(Tomcat 的Bootstrap类即由System类加载器加载)。文章源自JAVA秀-https://www.javaxiu.com/22499.html

    文章源自JAVA秀-https://www.javaxiu.com/22499.html

这些类加载器的工作原理是一样的,区别是它们的加载路径不同,也就是说 findClass 这个方法查找的路径不同。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

双亲委托机制是为了保证一个 Java 类在 JVM 中是唯一的,假如你不小心写了一个与 JRE 核心类同名的类,比如 Object 类,双亲委托机制能保证加载的是 JRE 里的那个 Object 类,而不是你写的 Object 类。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

这是因为 AppClassLoader 在加载你的 Object 类时,会委托给 ExtClassLoader 去加载,而 ExtClassLoader 又会委托给 BootstrapClassLoader,BootstrapClassLoader 发现自己已经加载过了 Object 类,会直接返回,不会去加载你写的 Object 类。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

这里请注意,类加载器的父子关系不是通过继承来实现的,比如 AppClassLoader 并不是 ExtClassLoader 的子类,而是说 AppClassLoader 的 parent 成员变量指向 ExtClassLoader 对象。同样的道理,如果你要自定义类加载器,不去继承 AppClassLoader,而是继承 ClassLoader 抽象类,再重写 findClass 和 loadClass 方法即可,Tomcat 就是通过自定义类加载器来实现自己的类加载逻辑。不知道你发现没有,如果你要打破双亲委托机制,就需要重写 loadClass 方法,因为 loadClass 的默认实现就是双亲委托机制。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

2、类加载器的源码

文章源自JAVA秀-https://www.javaxiu.com/22499.html

我们自定义类加载器就需要重写ClassLoader的loadClass方法。文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

-     Tomcat 的类加载机制     -文章源自JAVA秀-https://www.javaxiu.com/22499.html

1、加载机制的特点

  • 隔离性:Web应用类库相互隔离,避免依赖库或者应用包相互影响。设想一下,如果我们 有两个Web应用,一个釆用了Spring 2.5, 一个采用了Spring 4.0,而应用服务器使用一个 类加载器加载,那么Web应用将会由于Jar包覆盖而导致无法启动成功;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 灵活性:既然Web应用之间的类加载器相互独立,那么我们就能只针对一个Web应用进行 重新部署,此时该Web应用的类加载器将会重新创建,而且不会影响其他Web应用。如果 釆用一个类加载器,显然无法实现,因为只有一个类加载器的时候,类之间的依赖是杂 乱无章的,无法完整地移除某个Web应用的类;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 性能:由于每个Web应用都有一个类加载器,因此Web应用在加载类时,不会搜索其他 Web应用包含的Jar包,性能自然高于应用服务器只有一个类加载器的情况。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

2、Tomcat 的类加载方案

文章源自JAVA秀-https://www.javaxiu.com/22499.html

一文讲透 Tomcat 的类加载机制!揭秘类加载核心文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 引导类加载器 和 扩展类加载器 的作⽤不变;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使⽤该变量,⽽是加载tomcat启动的类,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • Common 通⽤类加载器加载Tomcat使⽤以及应⽤通⽤的⼀些类,位于CATALINA_HOME/lib下,⽐如servlet-api.jar;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • Catalina ClassLoader ⽤于加载服务器内部可⻅类,这些类应⽤程序不能访问;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • SharedClassLoader ⽤于加载应⽤程序共享类,这些类服务器不会依赖;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • WebappClassLoader,每个应⽤程序都会有⼀个独⼀⽆⼆的Webapp ClassLoader,他⽤来加载本应⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的类。文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

tomcat 8.5 默认改变了严格的双亲委派机制:文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 从缓存中加载;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 如果缓存中没有,会先调用ExtClassLoader进行加载, 扩展类加载器是遵循双亲委派的,他会调用bootstrap,查看对应的lib有没有,然后回退给ExtClassLoader对扩展包下的数据进行加载;文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 如果未加载到,则从 /WEB-INF/classes加载;文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

文章源自JAVA秀-https://www.javaxiu.com/22499.html

  • 如果未加载到,则从 /WEB-INF/lib/*.jar 加载如果未加载到,WebAppclassLoader 会委派给SharedClassLoader,SharedClassLoad会委派给CommonClassLoader.....,依次委派给BootstrapClassLoader, 然后BootstrapClassLoader 在自己目录中查找对应的类如果有则进行加载,如果没有他会委派给下一级ExtClassLoader,ExtClassLoader再查找自己目录下的类,如果有则加载如果没有则委派给下一级……遵循双亲委派原则。文章源自JAVA秀-https://www.javaxiu.com/22499.html

3、分析应用类加载器的加载过程

应用类加载器为WebappClassLoader ,他的loadClass在他的父类WebappClassLoaderBase中。文章源自JAVA秀-https://www.javaxiu.com/22499.html

注:在37行英文注释中标注获取的是系统类加载器,但我们debug的时候会发现他是扩展类加载器,实际中我们可以推断出他应该是扩展类加载器,因为如果我们加载的类在扩展类加载器路径下已经存在的话,那我们直接调用系统类加载器是就是错误的了,下图为debug后获取的类加载器的验证。文章源自JAVA秀-https://www.javaxiu.com/22499.html

总结:tomcat打破了双亲委派的原则,实际是在应用类加载器中打破了双亲委派,其他类加载器还是遵循双亲委派的。文章源自JAVA秀-https://www.javaxiu.com/22499.html

阅读原文文章源自JAVA秀-https://www.javaxiu.com/22499.html

继续阅读
速蛙云 - 极致体验,强烈推荐!!!购买套餐就免费送各大视频网站会员!快速稳定、独家福利社、流媒体稳定解锁!速度快,全球上网、视频、游戏加速、独立IP均支持!基础套餐性价比很高!这里不多说,我一直正在使用,推荐购买:https://www.javaxiu.com/59919.html
weinxin
资源分享QQ群
本站是JAVA秀团队的技术分享社区, 会经常分享资源和教程; 分享的时代, 请别再沉默!
沙海
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定