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. 为什么需要自定义类加载器 网上 ...
随机推荐
- springboot系列总结(一)---初识springboot
Spring Boot是一个简化Spring开发的框架.用来监护spring应用开发,约定大于配置,去繁就简,just run 就能创建一个独立的,产品级的应用. 一说springboot ,Java ...
- ORB_SLAM2 Ubuntu16.04编译错误
Ubuntu14.04一切正常,迁移到Ubuntu16.04后编译报错,提示: /usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h:745:3: ...
- 过WAF的小思路
过WAF的小思路 前言 最近在学习了一波CMS漏洞,尝试看了几个菠菜站,有宝塔WAF...向WHOAMI大佬取经回来后,绕过了一个WAF.觉得是时候要认真总结一下了:) 前期的过程 菠菜采用的是Thi ...
- Pulsar の 保证消息的顺序性、幂等性和可靠性
原文链接:Pulsar の 保证消息的顺序性.幂等性和可靠性 一.背景 前面两篇文章,已经介绍了关于Pulsar消费者的详细使用和自研的Pulsar组件. 接下来,将简单分析如何保证消息的顺序性.幂等 ...
- VMware安装IPFire防火墙镜像
之后便可以通过WEB登录到管理页面(admin账号,密码是在上面配置的) 详细可参考:https://www.mobibrw.com/2016/4900
- log4J日志输出修改
1. log4j.rootLogger=DEBUG,INFO, console, log, error ###Console ### log4j.appender.console = org.apac ...
- 阶段总结-Java基础-超进阶
Gitee项目地址:https://gitee.com/zc10010/java_interview_guide/tree/master/知识点话术 项目叫话术,但是我觉得作为知识点学习是挺不错的. ...
- Apache Dolphin Scheduler - Docker Compose 详解
Apache DolphinScheduler 是一个分布式去中心化,易扩展的可视化 DAG 工作流任务调度系统.简称 DS,包括 Web 及若干服务,它依赖 PostgreSQL 和 Zookeep ...
- js 获取转换网址中文参数
var search = decodeURI(location.search).substr(1); console.log(search); decodeURI 方法返回一个已编码的统一资源标识符 ...
- dede织梦会员模板调用template下模板head.htm方法及解析变量
1.找到dedecms会员中心的的目录 member ,然后在目录下用编辑器打开config.php 加入对dede模板解释函数如下: //php脚本开始 //引入arc.partview.cla ...