JVM 双亲委派机制过程解析

双亲委派机制

标题

双亲委派是一个孩子向父亲方向,又从父亲向孩子方向的委派过程。

1.1向上委派

一个类在收到类加载请求后,不会自己加载这个类,而是把这个类加载请求向上委派给它的父类去完成,父类收到这个请求后又继续向上委派给自己的父类,以此类推,直到所有的请求委派到启动类加载器中。

委派过程:

在某个类加载器接收到类加载请求后,该加载器不会直接去加载类而是先查看缓存空间是否已经加载了该类,如果已加载就直接返回;如果缓存中不存在则委托给其父加载器去加载,加载过程也是先查询缓存,查到了就直接返回,没查到就传给父加载器加载,依次传递到顶层的Bootstrap类加载器

1.2向下委派

当父类加载器在接收到类加载请求后,发现自己也无法加载这个类(这个情况通常是因为这个类的Class文件在父类的加载路径中不存在)这时父类会把这个信息反馈给子类,并向下委派子类加载器来加载这个类,直到这个请求被成功加载,但是一直到自定义加载器都没有找到,JVM就会抛出ClassNotFund异常。

委派过程:

第一步: 启动类在加载路径下查找并加载Class文件,如果没有找到就交给扩展类加载器加载 第二步:扩展类加载器在它的加载路径下查找并加载Class文件,如果还是没有找到,再交给应用程序类加载器加载 第三步:应用程序类加载器在加载路径下查找并加载Class文件,如果还是没有找到,就交给自定义加载器进行加载 第四步:自定义加载器在用户指定的位置进行查找并加载Class文件,如果还是没有找到,JVM抛出ClassNotFund异常。这时类加载失败,JVM也启动失败。

1.3底层实现

查看底层源码显示类加载是调用类的loadClass(),方法中加锁进行类加载防止多线程并发问题,先在自己的缓存中查找,有直接返回按名字找到的Class<?>对象,没有就递归调用parent.loadclass(),在父加载器中也是先找缓存,有直接返回,没有就再次递归调用父加载器,直到到顶层的Bootstrap加载器也找不到就捕获抛出的ClassNotFoundException,然后尝试自己加载,加载成功就返回,不成功就会抛ClassNotFoundException返回上一层子加载器中加载,...,直到返回自定义类加载才调用自己的findClass()方法尝试进行加载。

1.4为什么需要双亲委派机制 | 双亲委托机制的好处

双亲委派机制最重要的功能是保证安全性。我们可以用反证法的思想,假设不使用双亲委派机制,黑客自定义一个java.lang.String类,类中定义了如用户登录时将信息发送到黑客邮箱等“病毒代码”,没有双亲委派机制,User自定义加载器就会直接看缓存中是否存在java.lang.String类,不存在就直接加载黑客定义的String类,JVM就可能误以为黑客自定义的java.lang.String类是系统的String类,导致“病毒代码”被执行,从而泄露用户信息。

而有了双亲委派机制,黑客自定义的java.lang.String类永远都不会被加载进内存,因为Bootstrap加载器会加载系统的java.lang.String类并返回,黑客自定义的String类就无法加载,这就有效防止Java的核心API类在运行时被篡改,保证了安全性,且通过双亲委派机制不会重复加载类,降低开销、节约资源。

1.5怎么破坏

重写调用类的loadClass()方法或者使用SPI,双亲委派机制并不是一种强制性的约束模型,而是Java设计者推荐给开发者的类加载器实现方式。

线程上下文类加载器,这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个,如果在应用程序的全局范围内都没有设置过的话,那么这个类加载器就是应用程序类加载器。像JDBC就是采用了这种方式。这种行为就是逆向使用了加载器,违背了双亲委派模型的一般性原则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值