双亲委派机制的意思是除了顶层的启动类加载器以外,其余的类加载器,在加载之前,都会委派给它的⽗加载器进⾏加载。这样⼀层层向上传递,直到祖先们都⽆法胜任,它才会真正的加载。
打个⽐⽅。有⼀个家族,都是⼀些听话的孩⼦。孙⼦想要买⼀块棒棒糖,最终都要经过爷爷过问,如果⼒所能及,爷爷就直接帮孙⼦买了。
但你有没有想过,“类加载的双亲委派机制,双亲在哪⾥?明明都是单亲?”
我们还是⽤⼀张图来讲解。可以看到,除了启动类加载器,每⼀个加载器都有⼀个parent,并没有所谓的双亲。但是由于翻译的问题,这个叫法已经⾮常普遍了,⼀定要注意背后的差别。2022清明节是几月几日?
面包花双亲委派机制
表示数量少的词语我们可以翻阅 JDK 代码的 ClassLoader#loadClass ⽅法,来看⼀下具体的加载过程。和我们描述的⼀样,它⾸先使⽤ parent 尝试进⾏类加载,parent 失败后才轮到⾃⼰。同时,我们也注意到,这个⽅法是可以被覆盖的,也就是双亲委派机制并不⼀定⽣效。
王者荣耀更新失败
ClassLoader#loadClass
年年有今日这个模型的好处在于 Java 类有了⼀种优先级的层次划分关系。⽐如 Object 类,这个毫⽆疑问应该交给最上层的加载器进⾏加载,即使是你覆盖了它,最终也是由系统默认的加载器进⾏加载的。
如果没有双亲委派模型,就会出现很多个不同的 Object 类,应⽤程序会⼀⽚混乱。
详谈双亲委派的好处
这种委托双亲的模式保证了Java核⼼不会被恶⼼篡改:
1. 启动类加载器可以抢在标准扩展类装载器之前去装载类,⽽标准扩展类装载器可以抢在类路径加载器之前去装载那个
类,类路径装载 器⼜可以抢在⾃定义类加载器之前去加载它。所以Java虚拟机先从最可信的Java核⼼API查类型,这是为了防⽌不可靠的类扮演被信任的类。
试想⼀下,⽹络上有个名叫java.lang.Integer的类,它是某个⿊客为了想混进java.lang包所起的名字,实际上⾥⾯含有恶意代码,但是这种伎俩在双亲模式加载体系结构下是⾏不通的,因为⽹络类加载器在加载它的时候,它⾸先调⽤双亲类加载器,这样⼀直向上委托,直到启动类加载器,⽽启动类加载 器在核⼼Java API⾥发现了这个名字的类,所以它就直接加载Java核⼼API的java.lang.Integer类,然后将这个类返回,所以⾃始⾃终⽹络上的 java.lang.Integer 的类是不会被加载的。
2. 但是如果这个移动代码不是去试图替换⼀个被信任的类(就是前⾯说的那种情况),⽽是想在⼀个被信任的包中插⼊
⼀个全新的类型,情况会怎样呢?
⽐如⼀个名为 java.lang.Virus的类,经过双亲委托模式,最终类装载器试图从⽹络上下载这个类,因为⽹络类装载器的双亲们都没有这个类(当然没有了,因为是病毒嘛)。假设成功下载了这个类,那你肯定会想,Virus和lang下的其他类痛在java.lang包下,暗⽰这个类是Java API的⼀部分,那么是不是也拥有修改Java.lang包中数据的权限呢?
答案当然不是,因为要取得访问和修改java.lang包中的权限,java.lang.Virus和java.lang下其他类必须是属于同⼀个运⾏时包的,什么是运⾏时包?运⾏时包是指由同⼀个类装载器装载的、属于同⼀个包的、多个类型的集合。考虑⼀下,java.lang.Virus和java.lang其他类是同⼀个类装载器装载的吗?不是的!java.lang.Virus是由⽹络类装载器装载的!
打破双亲委派机制(⾃定义加载器)
下⾯我们就来聊⼀聊可以打破双亲委派机制的⼀些案例。为了⽀持⼀些⾃定义加载类多功能的需求,Java 设计者其实已经作出了⼀些妥协。
案例⼀:tom cat
tomcat 通过 war 包进⾏应⽤的发布,它其实是违反了双亲委派机制原则的。简单看⼀下 tomcat 类加载器的层次结构。
陕西历史博物馆网上订票
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论