详细链接: https://www.processon.com/view/link/61e31970e0b34d1be7f8ac96
ClassLoader.loadClass()的类加载过程 加载:从磁盘上将.class的字节码文件加载到JVM内存中去
,此时会做一些简单的校验,校验通过后,会生成一个java.lang.Class对象,作为这个类各种数据再方法区的入口验证: 校验字节码文件的正确性,看看是否符合JVM字节码规范,比如魔数,主次版本号等准备: 将类中的静态变量分配内存并且赋默认值解析: 将符号引用(比如方法名)转变为直接引用(JVM内存地址),这就是所谓的静态链接
的过程
静态链接: 类加载期间,将符号引用转变为直接引用动态链接: 程序运行期间,将符号引用转变为直接引用,比如方法中调用方法,JVM解析的时候会对被调用的方法名指向一个内存地址,通过这个地址找到对应的方法,最常见的就是多态,有不同的实现,只有到运行的时候才知道
初始化: 对类的静态变量初始化为指定值,执行静态代码块 类被加载到方法区中包含
运行时常量池类型信息字段信息方法信息类加载器的引用对应class实例的引用 注意
: 类加载机制是懒加载,部署war包使用时才会加载,静态代码块比构造函数先执行,类没加载完,不会调用构造函数
类加载器和双亲委派机制
类加载器
引导类加载器(BootStrap): 加载jre/lib目录下的核心类库
拓展类加载器(Ext): 加载支撑JVM运行
的jre/lib/ext目录下的jar
应用程序类加载器(App): 加载classpath路径下的类包,主要是加载用户自己写的类
自定义类加载器: 加载用户自定义路径下的类。特殊需要的时候才自定义类加载器,比如Tomcat会自定义类加载器,默认是应用程序加载器
sum.misc.Launcher
可以理解为所有类的父类加载器,C++先初始化Launcher类后,在通过此类生成拓展类、应用程序类加载器等
问题
: 为什么引导类加载器不是Launcher类生成的
避免类的重复加载
沙箱安全机制
,保证核心类不被篡改
全盘委托机制
全盘委托是指当一个ClassLoder装载一个类时,除非显示的使用另外一个ClassLoder,该类所依赖及引用的类也由这个ClassLoder载入
如何自定义类加载器
代码思路
继承java.lang.ClassLoader类重写ClassLoader.findClass()方法,此方法通过IO读取自定类文件路径重写ClassLoader.loadClass()方法,加载类
打破双亲委派机制
加载一个类,不使用父加载器,直接由自定义类加载器加载类代码思路
重写ClassLoader.loadClass()方法后在里面调用父加载器的方法处添加判断逻辑,如果是自定义类路径,就调用自定义的findClass方法
Tomcat为什么要打破双亲委派机制
对于一个web容器来说,可能需要部署多个应用程序,不同的应用程序可能依赖相同类库的不同版本,但是双亲委派机制已经实现了避免重复类加载,因此要保证每个版本的类库是独立的,要保证相互隔离
部署在同一个web容器中相同类库的版本可以共享
,否则多个应用程序此时都是同一类库的版本,会导致进行加载多次,浪费资源处于安全方面考虑,Tomcat也有自己的类库,也需要进行隔离处理
,否则会导致与应用程序的类库混淆每个jsp对应一个类加载器,这样是为了方便热部署
Tomcat这种类加载机制是否违背了双亲委派机制
很显然是的,Tomcat为了实现隔离性,每个webappClassLoader加载自己目录下的类文件,不会传递给父加载器,打破了双亲委派机制首先自己尝试去加载某类,如果找不到再代理给父加载器,其目的是优先加载web应用自己定义的类,它父类加载器就是AppClassLoaderweb应用是通过Class.forName()调用交给系统类加载器的,因为Class.forName的默认类加载器是系统类加载器
Tomcat怎么实现热加载
单独用一个线程时刻去监听jsp文件路径下文件夹的变动,比如说1s监听一次,如果有变动,把之前的类加载器置空,再重新赋值最新的类加载器,之前的等待gc回收
Tomcat类加载图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)