[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的

 

Launcher启动类


本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是很是重要的
不过源码其实比较简单,接下来简单介绍一下
 
咱们先从启动类提及
有一个Launcher类   sun.misc.Launcher;
image_5b8be55e_4272
 
仔细看下这简短的几行注释,能够获得有用的信息
ps:直接IDE里面查看反编译的,看不到注释的,能够下载openJDK查看源码,个人这个版本是openjdk-8-src-b132-03_mar_2014
 
sun.misc.Launcher
这个类是系统用于启动主应用的启动器
 
构造方法 Launcher() 中作了四件事情
建立          扩展          类加载器
建立          应用程序    类加载器
设置ContextClassLoader
若是须要安装安全管理器 security manager
其中launcher是staitc的,因此初始化的时候就会建立对象,也就是触发了构造方法,因此初始化的时候就会执行上面四个步骤
image_5b8be55e_3add
 
ExtClassLoader 和  AppClassLoader  都是Launcher的静态内部类
image_5b8be55e_6921
并且,他们也都是ClassLoader的实现类
image_5b8be55e_3cb7
 
看下ExtClassLoader的建立中的关键几步
image_5b8be55e_77fe
 
也在看下AppClassLoader的建立中的关键几步
image_5b8be55e_7080
 
另外还有
Launcher类中的静态变量
image_5b8be55e_62a5
 
你应该能够想获得下面这三个究竟是什么东西,若是真不懂,你须要再去研究下
System.getProperty("sun.boot.class.path")
System.getProperty("java.ext.dirs")
System.getProperty("java.class.path")
 
 
 

ClassLoader的构造方法

 
 
前面说过,对于虚拟机来讲只有两种类加载器
启动类加载器以及其余全部,而其余全部都是java.lang.ClassLoader的子类
因此想要自定义类加载器,必需要继承实现ClassLoader
并且,咱们上面说到的,java给咱们提供的AppClassLoader 和 ExtClassLoader 也都是ClassLoader的子类
 
看下ClassLoader的构造方法 和变量parent
你会发现,其实构造方法实际上只有双参数版本这一种
第二个参数为parent,这个parent是一个ClassLoader,  用于记录他的  父    类加载器
 
无论调用哪一个构造方法
parent必然会被初始化
要么是你调用带参数的构造方法, 显式指定一个来设置parent
若是你不指定,默认的构造方法,会使用  getSystemClassLoader返回的AppClassLoader  设置parent
 
 
 
image_5b8be55e_2925
ps:
本文中的很多地方,我都在"父类加载器" 的"父 "和"类加载器"中间加了几个空格
千万不要理解成父类加载器  ,<父    类加载器> 指的是类加载器的加载顺序层级结构的优先顺序   而不是平时说的继承关系中的父类 父 意味着他的上一层级
 
getSystemClassLoader 获取AppClassLoader 的过程
image_5b8be55f_2f0b
 
那么再回头看一眼  应用程序   类加载器的构造
扩展  类加载器做为参数传递给了他,他最终调用的就是ClassLoader 的一个参数的构造方法  
将ExtClassLoader 设置为 AppClassLoader  的parent
image_5b8be55f_4098
 
而ExtClassLoader,他的parent 是null
image_5b8be55f_53e0
 
ps:启动  类加载器 是虚拟机的一部分,可能c/c++/java实现的,因此不是java语言的一部分
因此对于java自己来讲,能够说他是不存在的,可是JVM是知道他的
因此说,此处为null ,parent为null说明他的父    类加载器是启动类加载器   或者可能就是启动  类加载器自己

loadClass与findClass

想要实现类 加载器,须要继承ClassLoader
而且有两个重要的方法
看下两个重要方法的声明,你可能就感受出来了,想一想public 和 protected都是啥意思?
image_5b8be55f_6d2f
 
loadClass方法是类加载器执行   加载类逻辑   的方法,包括检查是否已经加载,调用父类加载,失败则本身尝试使用 findClass方法加载
findClass当前类加载器 实际执行加载二进制流的具体行为方法
 
Launcher.APPClassLoader中的loadClass方法,最终调用的是super.loadClass  , 实际上就是ClassLoader的loadClass方法
Launcher.ExtClassLoader  根本就没有实现本身的loadClass 方法,因此使用的也是ClassLoader中的
 
image_5b8be55f_66ff
 
再来看看ClassLoader的loadClass方法
他会调用parent的loadClass方法,若是他的parent不为空,将会一直调用父 类加载器, 直到最顶级的  启动   类加载器 
若是 启动   类加载器仍旧找寻不到, 那么调用自身的findClass 
image_5b8be55f_2ac5
 
若是本身调用findClass加载失败呢?
很显然, 函数调用结束以后,会返回到调用点位置,调用栈的形式嘛
也就是通过
image_5b8be55f_1e1a
必然要继续执行他的下一段
若是没抛出异常的话,就会走到下面这里
image_5b8be55f_5b1f
显然这就完成了一整个的双亲委派的类加载模式
 
image_5b8be55f_4c07
 

总结

Launcher做为启动器
建立了ExtClassLoader 以及AppClassLoader
他们都是ClassLoader的子类,而且ClassLoader有一个parent  指向他的父   类加载器
正是这个属性完成了自顶而下的 优先级层级顺序的肯定
对于sun内置的ExtClassLoader 以及AppClassLoader  以及启动  类加载器 Bootstrap  他们的层级为
Bootstrap>ExtClassLoader>ExtClassLoader
而且,他们各自有不一样的分工
经过ClassLoader的loadClass方法,肯定了他们的调用逻辑,也就是双亲委派机制
每一个层级都会向上传递类加载请求,只有上层  父     类加载器调用失败,才会本身尝试加载
双亲委派机制的意义重大,带来了更高的安全性等优势
不过他的实现逻辑倒是的确很简单
一个loadClass就搞定了
findClass是类加载器自身加载类的具体行为
因此,若是你不须要破坏双亲委派机制,只须要覆盖这个方法便可
若是你想要彻底自定义你的类加载器的逻辑机制,直接覆盖loadClass,固然,你可能还须要继续覆盖findClass
相关文章
相关标签/搜索