双亲委派机制是Java中非常重要的类加载机制,它保证了类加载的完整性和安全性,避免了类的重复加载。

们的Java在运行之前,首先需要把Java代码转换成字节码,即class文件。

然后JVM需要把字节码通过一定的方式加载到内存中的运行时数据区

这种方式就是类加载器(ClassLoader)。

再通过加载、验证、准备、解析、初始化这几个步骤完成类加载过程,然后再由jvm执行引擎的解释器和JIT即时编译器去将字节码指令转换为本地机器指令进行执行。

我们在使用类加载器加载类的时候,会面临下面几个问题:

  1. 如何保证类不会被重复加载?类重复加载会出现很多问题。
  2. 类加载器是否允许用户自定义?
  3. 如果允许用户自定义,如何保证类文件的安全性?
  4. 如何保证加载的类的完整性?

双亲委派机制的基本思想是:当一个类加载器试图加载某个类时,它会先委托给其父类加载器,如果父类加载器无法加载,再由当前类加载器自己进行加载。

这种层层委派的方式有助于保障类的唯一性,避免类的重复加载,并提高系统的安全性和稳定性。

双亲委派

image.png

image.png

案例

case1:自定义一个java.lang.String(与Java的核心API String是冲突的)类,加载时会从下面应用程序类加载器始向上走,每一个加载器查看自己是否加载过,如果没有加载过就继续向上,最后到启动类加载器(Bootstrap ClassLoader),启动类加载器发现自己已经加载过String类了,所以就不会再加载了,然后String加载就结束了(启动类加载器Bootstrap ClassLoader会加载Java的核心库JAVAHOME/jre/1ib/rt.jar、resources.jar或sun.boot.class.path路径下的内容,用于提供JVM自身需要的类,String类就属于这里面的一种;怎样判断是否加载过:类的完成类名必须一致,包括包名、加载这个类的 ClassLoader(指ClassLoader实例对象)必须相同); case2:比如我又定义一个类,经过应用程序类加载器,发现自己没被加载过而且应用程序加载器还有上层扩展类加载器,那么就会到扩展类加载器,扩展类加载器继续来判断自己是否加载过,如果发现自己没被加载过而且扩展类加载器还有上层启动类加载器,那么就会到启动类加载器,最后到启动类加载器后自己也没有加载过,然后开始尝试自己加载,加载成功就结束,加载失败,就退回扩展类加载器加载(这里加载成功或是失败是看自己的这个加载器是否有加载这个类的责任,每一个加载器都有一定的责任范围,在下面虚拟机自带的加载器介绍中可以看到加载器的可以加载哪些类),扩展类尝试加载,成功就结束,失败了就交给应用程序类加载器去加载,如果应用类加载器可以加载就加载成功结束,如果不可以加载就抛出异常;

原理

如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是看看自己是否加载过(如果加载过结束),然后看看有没有父类(如果有交给父类加载器执行); 如果父类加载器自己没有加载过还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器; 然后顶层加载器发现这个类还是没有被加载过,然后就会去尝试加载,加载成功就结束了,加载失败就退回到子类,让子类尝试去加载,这就是双亲委派模式。 父类加载器一层一层往下分配任务,如果子类加载器能加载,则加载此类,如果将加载任务分配至系统类加载器也无法加载此类,则抛出异常