双亲委派模型

双亲委派模型(Parents Delegation Model):

  • 定义:当一个类加载器接收到一个类的加载任务时,它并不会立即展开加载,而是将加载器任务委派给它的超类加载器去执行,每一层的类加载器都采用相同的方式,直至委派给最顶层的启动类加载器为止;如果超类加载器无法加载委派给它的类时,将加载任务退回给它的下一级类加载器去执行加载;
  • 按照双亲委派模型的规则,除了启动类加载器之外,所有的类加载器都拥有一个超类加载器

优点

  • 能够有效确保一个类的全局唯一性(同一个类只会被加载一次)

java.lang.ClassNotFoundException

显示调用下面两种方式可能会导致类加载异常:

  • Class.forName()
  • ClassLoader.getSystemClassLoader().loadClass()

知识点

  • JAVA虚拟机规范并没有要求类加载器的加载机制一定要使用双亲委派模型,只是建议采用这种方式
  • 比如Tomcat就是自行实现了类加载机制(当默认的类加载器接收到一个类的加载任务时先自行加载,当加载失败时才会委派给它的超类加载器执行加载,这同时也是Servlet规范推荐的一种做法)
  • 程序中如果没有显示指定类加载器,AppClassLoader就是任务委派的发起者

彩图

为什么要使用双亲委托这种模型呢?

因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

但是JVM在搜索类的时候,又是如何判定两个class是相同的呢?

JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class

既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?

因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,比如:我要加载网络上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法实现我的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader

results matching ""

    No results matching ""