什么是类加载器?

  • 这是官方给的定义

在 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加载,这和双亲委派刚好相反。

怎么实现一个自定义加载器

  1. 继承Classloder接口

  1. 重写构造方法

Tomcat实现自定义类加载器的更多相关文章

  1. 4.自定义类加载器实现及在tomcat中的应用

    了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器 一. 回顾类加载器的原理 还是这张图,类加载器的入口是c++调用java代码创建了J ...

  2. Tomcat内核之类加载器工厂

    Java虚拟机利用类加载器将类载入内存,以供使用.在此过程中类加载器要做很多的事情,例如读取字节数组.验证.解析.初始化等.而Java提供的URLClassLoader类能方便地将jar.class或 ...

  3. Java内存管理-掌握自定义类加载器的实现(七)

    勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇分析了ClassLoader的类加载相关的核心源码,也简单介绍了ClassLoa ...

  4. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  5. 还是Tomcat,关于类加载器的趣味实验

    一.前言 类加载器,其实是很复杂一个东西,想等到我完全什么都弄明白了再写出来,估计不太现实...现在只能是知道多少写多少吧. 首先,我提一个问题:在我们自己的servlet中(比如ssm中,contr ...

  6. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  7. java类加载器学习2——自定义类加载器和父类委托机制带来的问题

    一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...

  8. Java自定义类加载器与双亲委派模型

    其实,双亲委派模型并不复杂.自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用.但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行.可是自定义类 ...

  9. (转)JVM——自定义类加载器

    背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...

随机推荐

  1. k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-7

    Kubernetes Dashboard 创建CoreDNS [root@linux-node1 ~]# kubectl create -f coredns.yaml [root@linux-node ...

  2. 【Python机器学习实战】决策树与集成学习(四)——集成学习(2)GBDT

    本打算将GBDT和XGBoost放在一起,但由于涉及内容较多,且两个都是比较重要的算法,这里主要先看GBDT算法,XGBoost是GBDT算法的优化和变种,等熟悉GBDT后再去理解XGBoost就会容 ...

  3. vue 之 v-model

    v-model虽然很像使用了双向数据绑定的 Angular 的 ng-model,但是 Vue 是单项数据流,v-model 只是语法糖而已: <input v-model="sth& ...

  4. C++模板简介

    模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数.返回值取得任意类型. 模板是一种对类型进行参数化的工具: 通常有两种形式:函 ...

  5. WEB漏洞——XXE

    XXE漏洞又称XML外部实体注入(XML External Entity) 介绍XXE漏洞前先说一下什么是XML XML语言 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据定义数据类 ...

  6. 循环神经网络LSTM RNN回归:sin曲线预测

    摘要:本篇文章将分享循环神经网络LSTM RNN如何实现回归预测. 本文分享自华为云社区<[Python人工智能] 十四.循环神经网络LSTM RNN回归案例之sin曲线预测 丨[百变AI秀]& ...

  7. Git 系列教程(11)- 分支简介

    前言 很多版本控制系统都有分支这个概念 使用分支意味着可以将日常工作从主线上脱离,从而避免影响主线 Git 鼓励在工作流程中频繁使用分支和合并 Git 是如何保存数据的 Git 保存的不是文件的变化或 ...

  8. Jest中Mock网络请求

    Jest中Mock网络请求 最近需要将一个比较老的库修改为TS并进行单元测试,修改为TS还能会一点,单元测试纯粹是现学现卖了,初学Jest框架,觉得在单元测试中比较麻烦的就是测试网络请求,所以记录一下 ...

  9. CodeForces - 706B Interesting drink(二分查找)

    Interesting drink Problem Vasiliy likes to rest after a hard work, so you may often meet him in some ...

  10. PTA 面向对象程序设计 7-1 2017Final 圆周率山

    7-1 2017Final 圆周率山 为了参加学校的社团风采展,怡山小学数学组的同学们决定画一座圆周率山,以宣传圆周率. 已知圆周率为:3. 1415926535 8979323846 2643383 ...