JVM类加载之双亲委派机制
一、什么是双亲委派机制?
所谓的双亲委派,就是先让父类加载器试图加载该Class,只有父类加载器无法加载该Class时,子类才从自己的类路径中加载该类。
二、双亲委派机制的原理是什么?
如果一个类加载器收到了类加载器请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还在存在其父类加载器,则进一步向上委托,一次递归,请求最终将达到顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,如果父类加载器无法完成该加载任务,子加载器才会尝试自己去加载。
三、如何实现双亲机制?
loadClass(String,boolean)函数即实现了双亲委派模型。
1.首先,检查一下指定名称的类是否已经加载过,如果加载过,就不需要再加载,直接返回。
2.如果此类没有加载过,再判断一下是否有父类加载器;如果有父类加载器,则由父类加载器加载(即调用parent.loadClass(name,false);)或者调用启动类加载器(Bootstrap)进行加载。加resolve参数以及方法resolve()的情况,loadClass(String name,boolean resolve)则是一个重载方法,resolve()方法是一个是否需要在加载时同时进行解析的方法。
3.如果父类加载器及Boootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass(String)方法来完成类加载。
4.抽象类ClassLoader的findClass函数默认是抛出异常的,要在父类加载器无法加载的时候调用,且在函数方法里面实现一个指定类(通常为一个字节组)转换为Class对象,这时候就得调用defineClass(String name,byte[] b,int off,int len)方法。
5.URLClassLoader中存在一个URLClassPath类,通过这个类可以找到要加载的字节码流。主要是根据传递过来的URL数组中的路径判断是文件还是jar包,然后根据不同的路径创建FileLoader或JarLoader或默认Loader类去加载相应路径下的class文件,而当JVM调用findClass()方法时,就由这三个加载器其中的一个将Class文件的字节码流加载到内存中,最后利用字节码流创建类的Class对象。
6.拓展类加载器ExtClassLoader(Extensioin ClassLoader)和系统类加载器AppClassLoader(Application ClassLoader)都继承自URLClassLoader,是Sun.misc.Launcher的静态内部类。Sun.misc.Launcher主要被用于启动主要应用程序。
四、双亲委派机制的好处/优势
采用双亲委任机制的好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关系可以避免类的重复加载,当父类加载器已经加载了该类时,就没必要让子加载器再加载一次。其次,考虑到安全因素,java核心api中定义类型不会被随意替换,可以防止核心API库被随意篡改。
参考: https://www.cnblogs.com/wxd0108/p/6681618.html