::我的理解

本质上,就是对类的加载顺序的问题。好处在于

  1. 避免类的重复加载。

    笔记

避免类的重复加载,JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就属于两个不同的类(比如,Java中的Object类,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,如果不采用双亲委派模型,由各个类加载器自己去加载的话,系统中会存在多种不同的Object类)

  1. 保护程序安全,防止核心API被随意篡改

笔记

保护程序安全,防止核心API被随意篡改,避免用户自己编写的类动态替换 Java的一些核心类,比如我们自定义类:java.lang.String

执行过程

技巧💡

先使用父类加载器,如果失败在到子类加载器。

  • 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
  • 如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
  • 如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式

破坏双亲委派机制

  • 双亲委派模型并不是一个强制性的约束模型,而是Java设计者推荐给开发者的类加载器实现方式,可以“被破坏”,只要我们自定义类加载器,重写loadClass()方法,指定新的加载逻辑就破坏了,重写findClass()方法不会破坏双亲委派。
  • 双亲委派模型有一个问题:顶层ClassLoader,无法加载底层ClassLoader的类。典型例子JNDI、JDBC,所以加入了线程上下文类加载器(Thread Context ClassLoader),可以通过Thread.setContextClassLoaser()设置该类加载器,然后顶层ClassLoader再使用Thread.getContextClassLoader()获得底层的ClassLoader进行加载。
  • Tomcat中使用了自定ClassLoader,并且也破坏了双亲委托机制。每个应用使用WebAppClassloader进行单独加载,他首先使用WebAppClassloader进行类加载,如果加载不了再委托父加载器去加载,这样可以保证每个应用中的类不冲突。每个tomcat中可以部署多个项目,每个项目中存在很多相同的class文件(很多相同的jar包),他们加载到jvm中可以做到互不干扰。
  • 利用破坏双亲委派来实现**代码热替换**(每次修改类文件,不需要重启服务)。因为一个Class只能被一个ClassLoader加载一次,否则会报java.lang.LinkageError。当我们想要实现代码热部署时,可以每次都new一个自定义的ClassLoader来加载新的Class文件。JSP的实现动态修改就是使用此特性实现。