vlambda博客
学习文章列表

jvm 双亲委派模式

覆盖第三方包的代码,这里用到了一个不常见的Java知识,双亲委派机制。利用双亲委派机制,可以很巧妙的重写第三方包的部分逻辑,不必维护第三方包的代码。为了更好的理解双亲委派机制,需要先了解类加载与类加载器相关知识。

什么是类加载机制?

Java虚拟机把编译后的Class文件加载进内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。对于任意一个类,都需要由加载他的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性。


Java的类加载器有四种

  • Bootstrap ClassLoader:根类加载器,负责加载Java的核心类,它不是java.lang.ClassLoader的子类,而是由JVM自身实现

  • Extension ClassLoader:扩展类加载器,扩展类加载器的加载路径是JDK目录下 jre/lib/ext,通过扩展类加载器的getParent() 方法返回的是null,实际上扩展类加载器的父类是根加载器

  • System ClassLoader:系统(应用)类加载器,它负责在JVM启动时加载来自java 命令的 -classpath选项,或者通过CLASSPATH环境变量所指定的jar包和类路径。

  • User ClassLoader:自定义类加载器,加载用户创建的自定义类



什么是双亲委派机制?

某个类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,子加载器才会尝试自己去加载。


双亲委派机制作用

  1. 避免类的重复加载。当父类加载器加载了该类时,子类加载器就不会再加载一次。

  2. 防止java核心API被随意替换。


如何破坏双亲委派模型?

第一次破坏:向前兼容,类加载器和抽象类java.lang.ClassLoader则是JDK1.0时候就已经存在JDK1.2之后的java.lang.ClassLoader添加了一个新的proceted方法findClass(),自定义的类加载逻辑写到findClass()方法中。在loadClass()方法的逻辑里,如果父类加载器加载失败,则会调用自己的findClass()方法来完成加载,这样就可以保证新写出来的类加载器是符合双亲委派模型的。

第二次破坏:加载SPI接口实现类,一个典型的例子便是jdbc服务,它的代码由启动类加载器去加载jdbc的目的是对进行统一的管理,它要调用独立厂商实现部署在应用程序classpath下的JDBC接口提供者的代码但启动类加载器不可能“认识”这些代码,为了解决这个问题,便引入了线程上下文件类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承一个;如果在应用程序的全局范围内都没有设置过,那么这个类加载器默认就是应用程序类加载器有了线程上下文类加载器,jdbc服务使用这个线程上下文类加载器去加载所需要的jdbc实现类的代码。

第三次破坏:热部署,为了实现热插拔,热部署,模块化,意思是添加一个功能或减去一个功能不用重启,只需要把这模块连同类加载器一起换掉就实现了代码的热替换。