什么是类加载器?

  • 这是官方给的定义

在 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. Python安装环境配置和多版本共存

    Python安装环境配置和多版本共存 1.环境变量配置: (1) 右键点击"计算机",然后点击"属性" (2) 然后点击"高级系统设置" ( ...

  2. 性能测试工具JMeter 基础(二)—— 主界面介绍

    主界面介绍 JMeter的主界面主要分为菜单导航栏.工具栏.计划树标签栏.内容栏 菜单导航栏:全部的功能的都包含在菜单栏中 工具栏:相当于菜单栏常用功能的快捷按钮 计划树标签栏:显示测试用例(计划)相 ...

  3. Python图像分割之区域增长法

    原文链接:https://blog.csdn.net/sgzqc/article/details/119682864 一.简介 区域增长法是一种已受到计算机视觉界十分关注的图像分割方法.它是以区域为处 ...

  4. C# AutoMaper简单使用

    AutoMapper它是一种对象与对象之间的映射器,让AutoMapper有意思的就是在于它提供了一些将类型A映射到类型B这种无聊的实例,只要B遵循AutoMapper已经建立的惯例,那么大多数情况下 ...

  5. AntDesign VUE:上传组件图片/视频宽高、文件大小、image/video/pdf文件类型等限制(Promise、Boolean)

    文件大小限制 - Promise checkFileSize(file, rules) { return new Promise((resolve, reject) => { file.size ...

  6. Emit优化反射(属性的设置与获取)

    在频繁的通过反射来设置和获取属性的值时是比较耗时的,本章通过Emit技术优化反射来提高获取和设置属性值的效率 一.实现代码: /// <summary> /// 设置器委托 /// < ...

  7. ysoserial exploit/JRMPClient

    ysoserial exploit/JRMPClient 上一篇文章讲到,当服务器反序列化payloads/JRMPListener,即会开启端口监听.再使用exploit/JRMPClient模块发 ...

  8. 【转】.net core开发windows服务

    .net core开发windows服务 文建Blog

  9. 一文梳理清楚mysql各种锁

    全局锁: 1.FTWRL(读锁) 用于做全库的逻辑备份 加锁:FLUSH TABLES WITH READ LOCK 解锁:unlock tables 表级锁: 1.表锁 表锁的读锁和写锁 加锁:lo ...

  10. STM32CbueIDE 体验

    STM32CbueIDE 体验 下载安装 官网下载链接:https://www.st.com/zh/development-tools/stm32cubeide.html. 软件启动时会令设置工作目录 ...