Java的类加载器
耳熟能详,不,眼熟能祥的模型图
image-20200410181230808.png
简单说一下:
上图不太精确,首先他们3个不是父子继承关系,只是上下级关系。
App接到任务不管能不能处理,先请示领导Ext
Ext接到任务不管能不能处理,先请示领导BootStrap
BootStrap接到任务,发现自己能处理,就处理了,不能处理,就还给Ext
Ext同理,自己处理或者还给App
什么是类加载:
简单的说,类加载就是把 *.class文件从磁盘干到jvm内存里
那么这里就需要做如下工作:
1. 找到*.class文件在磁盘的位置
2. 把这个class文件变成一个class实例
3. 1,2之间有一些验证操作
从代码的角度来看:
ClassLoader.java是所有类加载器的顶级类(不包含启动类加载器)
java代码的所有类加载器都会继承到ClassLoader,ClassLoader里有loadClass(), findClass(), defineClass()
类加载时会调用loadClass(),loadClass()里 会调用findClass(), findClass()里调用defineClass()
findClass顾名思义就是找到*.class文件,根据全限定名去找
defineClass是把找到的文件转换成class实例(这是jdk源码注释:Converts an array of bytes into an instance of class)
loadClass在最外层被调用
从tomcat的WebappClassLoader来看:
tomcat的webapp类加载器用来加载webapp下的资源,这样是为了做到app隔离,避免全限定名相同的类加载混乱
webappClassLoader的loadClass()方法在加载之前会做一系列判断,比如被加载类是不是j2se的类,如果是就直接用启动类加载器加载
再比如:是否是非webapp专有的资源,如果是,就让其上一级加载
image-20200410190951121.png image-20200410191014053.png截图放不下,就不在贴出了,主要就是通过路径什么的来加以限定,确定这个类是否真的需要有WebappClassLoader来加载
如果真需要WebappClassLoader加载,那么就执行重写的findClass(name)方法,在findClass里调用自己的findClassInternal()方法一顿搞,最后来到defineClass()里,得到class实例,这里的defineClass()方法是父类方法(SecureClassLoader,SecureClassLoader也会继续调用他的父类ClassLoader里的defineClass方法, ClassLoader里继续会调用defineClass1(),看到数字结尾的方法,那就是native方法了)
再往后呢,如果webappClassLoader没成功加载,加载不了了,那咋办了。这就要去找领导了,让领导处理吧
image-20200410192922031.png
总结下:tomcat打破双亲委派是在加载webapp自己的类时,只用WebappClassLoader加载,而不会向上传递,找自己的上级处理,自己能加载就加载了
补充一点:jdk里的ExtClassLoader,AppClassLoader都继承子URLClassLoader,其实,他们都是通过类的全限定名去findClass,只不过ExtClassLoader,AppClassLoader在加载时会通过自身的加载路径范围与被加载类的全限定名比较,看看是否属于自己的权利范围。
image-20200410193522584.png
网友评论