Tomcat实现自定义类加载器
什么是类加载器?
- 这是官方给的定义
在 Java 虚拟机的实现中,初始类可以作为命令行参数提供。 或者,该实现可以提供一个初始类,该类设置一个类加载器,该类加载器依次加载应用程序。 初始类的其他选择也是可能的,只要它们与上一段中给出的规范一致。
所谓类加载器,就是用于加载Java类到Java虚拟机中的组件,它负责读取Java字节码,并转换成java.lang.Class类的一个实例,使字节码.class 文件得以运行。一般类加载器负责根据一个指定的类找到对应的字节码,然后根据这些字节码定义一个Java类。
类加载器在实际使用中给我们带来的好处是,它可以使Java类动态地加载到JVM中并运行,即可在程序运行时再加载类,提供了很灵活的动态加载方式。
站在程序员的角度来看,Java 类加载器可以分为三种。
- 启动类加载器(Bootstrap ClassLoader):加载对象是Java核心库,把一些核心的Java类加载进JVM中,这个加载器使用原生代码(C/C++)实现,并不是继承java.lang.ClassLoader,它是所有其他类加载器的最终父加载器,负责加载<JAVA_HOME>/jre/lib目录下JVM指定的类库。其实它属于JVM整体的一部分,JVM一启动就将这些指定的类加载到内存中,避免以后过多的I/O操作,提高系统的运行效率。启动类加载器无法被Java程序直接使用。
- 扩展类加载器(Extension ClassLoader):加载的对象为Java的扩展库,即加载<JAVA_HOME>/jre/lib/ext目录里面的类。这个类由启动类加载器加载,但因为启动类加载器并非用Java 实现,已经脱离了Java体系,所以如果尝试调用扩展类加载器的getParent()方法获取父加载器会得到null。然而,它的父类加载器是启动类加载器。
- 应用程序类加载器((Application ClassLoader):亦叫系统类加载器(System ClassLoader),它负责加载用户类路径(CLASSPATH)指定的类库,如果程序没有自己定义类加载器,就默认使用应用程序类加载器。它也由启动类加载器加载,但它的父加载类被设置成了扩展类加载器。如果要使用这个加载器,可通过ClassLoader.getSystemClassLoader()获取。
双亲委派
双亲委派模型会在类加载器加载类时首先委托给父类加载器加载,除非父类加载器不能加载才自己加载。
使用双亲委派模型,Java类随着它的加载器一起具备了一种带有优先级的层次关系,通过这种层次模型,可以避免类的重复加载,也可以避免核心类被不同的类加载器加载到内存中造成冲突和混乱,从而保证了Java核心库的安全。
- 示范
最顶级的类加载器Bootstrap是由c++语言写的,所以打印出来是Null
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=2921:D:\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;
后面的这些就是应用类加载器
D:\original\apache-tomcat-8.5.70-src\target\classes;D:\software\maven_repository\org\easymock\easymock\3.4\easymock-3.4.jar;D:\software\maven_repository\org\objenesis\objenesis\2.2\objenesis-2.2.jar;D:\software\maven_repository\org\apache\ant\ant\1.7.0\ant-1.7.0.jar;D:\software\maven_repository\org\apache\ant\ant-launcher\1.7.0\ant-launcher-1.7.0.jar;D:\software\maven_repository\wsdl4j\wsdl4j\1.6.2\wsdl4j-1.6.2.jar;D:\software\maven_repository\javax\xml\jaxrpc-api\1.1\jaxrpc-api-1.1.jar;D:\software\maven_repository\org\eclipse\jdt\core\compiler\ecj\4.5.1\ecj-4.5.1.jar" org.apache.catalina.startup.Test
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@29453f44
null
Process finished with exit code 0
为什么TOMCAT要破坏双亲委派?
我们知道,Tomcat是web容器,那么一个web容器可能需要部署多个应用程序。
不同的应用程序可能会依赖同一个第三方类库的不同版本,但是不同版本的类库中某一个类的全路径名可能是一样的。
如多个应用都要依赖hollis.jar,但是A应用需要依赖1.0.0版本,但是B应用需要依赖1.0.1版本。这两个版本中都有一个类是com.hollis.Test.class。
如果采用默认的双亲委派类加载机制,那么是无法加载多个相同的类。
所以,Tomcat破坏双亲委派原则,提供隔离的机制,为每个web容器单独提供一个WebAppClassLoader加载器。
Tomcat是怎么破坏双亲委派的呢?
- 通过实现自定义加载器
Tomcat 本身有commonclassloader来管理,不去跟应用程序所冲突
每一个应用都会生成一个类加载器的实例 webclassloader
管理一个目录 这个目录 就是web-inf
这个目录由findclassloader来指定
webclassloader的上一级类加载器就是commonclassloader
整个层级关系就是这样的
双亲委派变五亲委派(不是
webclassloader-->commonclassloader-->appclassloader-->extclassloader-->bootstrapclassloader
Tomcat的类加载机制:为了实现隔离性,优先加载 Web 应用自己定义的类,所以没有遵照双亲委派的约定,每一个应用自己的类加载器——WebAppClassLoader负责加载本身的目录下的class文件,加载不到时再交给CommonClassLoader加载,这和双亲委派刚好相反。
怎么实现一个自定义加载器
- 继承Classloder接口
- 重写构造方法
Tomcat实现自定义类加载器的更多相关文章
- 4.自定义类加载器实现及在tomcat中的应用
了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器 一. 回顾类加载器的原理 还是这张图,类加载器的入口是c++调用java代码创建了J ...
- Tomcat内核之类加载器工厂
Java虚拟机利用类加载器将类载入内存,以供使用.在此过程中类加载器要做很多的事情,例如读取字节数组.验证.解析.初始化等.而Java提供的URLClassLoader类能方便地将jar.class或 ...
- Java内存管理-掌握自定义类加载器的实现(七)
勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇分析了ClassLoader的类加载相关的核心源码,也简单介绍了ClassLoa ...
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- 还是Tomcat,关于类加载器的趣味实验
一.前言 类加载器,其实是很复杂一个东西,想等到我完全什么都弄明白了再写出来,估计不太现实...现在只能是知道多少写多少吧. 首先,我提一个问题:在我们自己的servlet中(比如ssm中,contr ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- java类加载器学习2——自定义类加载器和父类委托机制带来的问题
一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...
- Java自定义类加载器与双亲委派模型
其实,双亲委派模型并不复杂.自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用.但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行.可是自定义类 ...
- (转)JVM——自定义类加载器
背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...
随机推荐
- k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-7
Kubernetes Dashboard 创建CoreDNS [root@linux-node1 ~]# kubectl create -f coredns.yaml [root@linux-node ...
- 【Python机器学习实战】决策树与集成学习(四)——集成学习(2)GBDT
本打算将GBDT和XGBoost放在一起,但由于涉及内容较多,且两个都是比较重要的算法,这里主要先看GBDT算法,XGBoost是GBDT算法的优化和变种,等熟悉GBDT后再去理解XGBoost就会容 ...
- vue 之 v-model
v-model虽然很像使用了双向数据绑定的 Angular 的 ng-model,但是 Vue 是单项数据流,v-model 只是语法糖而已: <input v-model="sth& ...
- C++模板简介
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函 ...
- WEB漏洞——XXE
XXE漏洞又称XML外部实体注入(XML External Entity) 介绍XXE漏洞前先说一下什么是XML XML语言 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据定义数据类 ...
- 循环神经网络LSTM RNN回归:sin曲线预测
摘要:本篇文章将分享循环神经网络LSTM RNN如何实现回归预测. 本文分享自华为云社区<[Python人工智能] 十四.循环神经网络LSTM RNN回归案例之sin曲线预测 丨[百变AI秀]& ...
- Git 系列教程(11)- 分支简介
前言 很多版本控制系统都有分支这个概念 使用分支意味着可以将日常工作从主线上脱离,从而避免影响主线 Git 鼓励在工作流程中频繁使用分支和合并 Git 是如何保存数据的 Git 保存的不是文件的变化或 ...
- Jest中Mock网络请求
Jest中Mock网络请求 最近需要将一个比较老的库修改为TS并进行单元测试,修改为TS还能会一点,单元测试纯粹是现学现卖了,初学Jest框架,觉得在单元测试中比较麻烦的就是测试网络请求,所以记录一下 ...
- CodeForces - 706B Interesting drink(二分查找)
Interesting drink Problem Vasiliy likes to rest after a hard work, so you may often meet him in some ...
- PTA 面向对象程序设计 7-1 2017Final 圆周率山
7-1 2017Final 圆周率山 为了参加学校的社团风采展,怡山小学数学组的同学们决定画一座圆周率山,以宣传圆周率. 已知圆周率为:3. 1415926535 8979323846 2643383 ...