做者:毕来生
微信:878799579
首先咱们来描述一个小说场景,经过这个场景在去理解咱们相关的类加载器的执行以及双亲委派模型。java
上古时代有逍遥派和万魔宗两个宗派,互相对立。逍遥派比万魔门更增强势。巅峰战力更高。安全
有一天万魔宗一名长老之子的仆人外出猎物期间杀掉了一小队逍遥派历练弟子。惋惜手脚不干净,留下了线索。被逍遥派探子发现了本身师弟师妹被杀。消息传回宗门后。微信
逍遥派收到此消息后大怒,发出战书。定要万魔门给个交代。万魔门宗主收到战书后一脸莫名其妙,这么点小事也来烦我?不知道我修炼有多重要吗?不就是杀了几我的么?遂叫来大长老,“大长老你看看这战书,这么点事情还办很差还要我亲自来处理?要你有什么用 ? 你去准备点东西把这件事情处理一下。退下吧!”工具
大长老灰溜溜的回去。叫来本身的儿子。上去就抽了一巴掌,看看你办的好事。我无论了。你本身想办法解决,解决不了就别回来了。oop
大长老之子哭丧着脸回到了本身的府邸。从本身的宝库挑出一些珍宝前去拜访逍遥门,看能不能经过这些珍宝解决这件事情。结果,到了逍遥派门前,守卫一看就这么点东西就想交代。对万魔门大长老之子说:"赶忙滚关进滚,就这么点东西还想给咱们交代?把杀了咱们师弟师妹的人带过来,否则这事儿不算完。“spa
大长老之子那叫一个憋屈呀,宝物什么的他们也不要,看样子他们是铁了心想要哪些杀了他们的罪魁祸首。那就把他们交出去把。他们惹的事。让他们本身解决。遂派人抓捕这些人送往逍遥派,此事才得以平息。code
下面咱们经过一张关系图来分析一下咱们的故事场景以及对应咱们类加载器之间的关系blog
经过这个图咱们能够了解到咱们的小故事中与咱们Java中的类加载器的对应关系。继承
一、宗主:引导类加载器。这个类加载使用C++语言实现的,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必因为虚拟机是按照文件名识别加载jar包的,如rt.jar,若是文件名不被虚拟机识别,即便把jar包丢到lib目录下也是没有做用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。递归
二、长老:拓展类加载器。,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库,开发人员能够直接使用标准扩展类加载器。
三、长老之子:系统类加载器。,它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是咱们常常用到的classpath路径,开发者能够直接使用系统类加载器,通常状况下该类加载是程序中默认的类加载器,经过ClassLoader类中的getSystemClassLoader()方法能够获取到该类加载器。
四、长老之子的下人:自定义类加载器。,它须要以下步骤才能够实现自定义效果
4.1. 继承java.lang.ClassLoader
4.2. 重写findClass()方法
4.3 调用defineClass()方法
一、什么是双亲委派模型?
特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,若是父类加载器能够完成类加载任务,就成功返回;只有父类加载器没法完成此加载任务时,才本身去加载。
二、双亲委派模型是如何使用的?
1)咱们在自定义加载器中查找是否有须要加载的文件,若是已经加载过,直接返回字节码。
对应故事场景为:长老之子的下人本身解决不了,找到长老之子
2)若是自定义加载器没有加载过,则询问上一层加载器(即AppClassLoader)是否已经加载过。
对应故事场景为:长老之子携带宝物前去拜访解决此事
3) 若是没有加载过,则询问上一层加载器(ExtClassLoader)是否已经加载过。
对应故事场景为:大长老解决此事
4) 若是没有加载过,则继续询问上一层加载(BoopStrap ClassLoader)是否已经加载过
对应故事场景为:宗主解决此事
5) 若是BoopStrap ClassLoader依然没有加载过,则到本身指定类加载路径下("sun.boot.class.path")
查看是否有对应XXX.class字节码,有则返回,没有则通知下一层加载器ExtClassLoader到本身指定的
类加载路径下(java.ext.dirs)查看
6) 最后到自定义类加载器指定的路径尚未找到对应XXX.class字节码,则抛出异常ClassNotFoundException
一、好比两个类A和类B都要加载Integer类:
若是不用委托而是本身加载本身的,那么类A就会加载一份Integer字节码,而后类B又会加载一份Integer字节码,这样内存中就出现了两份Integer字节码。
若是使用委托机制,会递归的向父类查找,也就是首选用Bootstrap尝试加载,若是找不到再向下。这里的Integer就能在Bootstrap中找到而后加载,若是此时类B也要加载Integer,也从Bootstrap开始,此时Bootstrap发现已经加载过了Integer那么直接返回内存中的Integer而不须要从新加载,这样内存中就只有一份Integer的字节码了。
二、 安全性:
由于ClassLoader加载的class文件来源不少,好比编译器编译生成的class、其余工具生成的字节码。而有一些一些来源的class文件是不安全的,好比咱们自定义一个java.lang.Integer类来覆盖jdk中默认的Integer类。里面写这么一句代码 System.exit(0);
初始化这个Integer的构造器是会退出JVM,破坏应用程序的正常进行,若是使用双亲委派机制的话该Integer类永远不会被调用,觉得委托BootStrapClassLoader加载后会加载JDK中的Integer类而不会加载自定义的这个