jvm 类加载器

322 阅读3分钟

类加载器

在jvm中类加载器是有等级之分的,从高到低分别是:根加载器/启动类加载器(Bootstrp loader),扩展类加载器(ExtClassLoader),应用程序类加载器(AppClassLoader/Application ClassLoader),在下面还有自定义加载器。

  1. 根加载器用于加载核心类库/本地方法类(%JAVA_HOME%/lib目录下的 rt.jar 、resources.jar 、charsets.jar等 jar 包和类)
  2. 扩展类加载器用于加载JDK内部实现的扩展类。%JRE_HOME%/lib/ext 目录下的 jar 包和类以及被 java.ext.dirs 系统变量所指定的路径下的所有类。
  3. 应用程序类加载器加载程序中的文件,也就是面向我们用户,它负责加载用户类路径(ClassPath)上所指定的类库。
  4. 自定义加载器用于满足自己的特殊需求。

双亲委派机制

有这么多类加载器,我们应该如何选择加载器来加载我们的类呢?这时我们就需要使用双亲委派机制了。
应用程序是由三种类加载器互相配合从而实现类加载,除此之外还可以加入自己定义的类加载器。

双亲委派模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。这里的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。并且父子类关系就行我上面说的类加载器一样。

image.png

工作流程:一个类加载器会将收到的类加载请求发送到自己的父类加载器,一直到传送到顶级加载器。只有父类加载器无法加载该类才会交给子类去处理。

这么做的好处:使得 Java 类随着它的类加载器一起具有一种带有优先级的层次关系,从而使得基础类得到统一。

类加载器之间的父子关系一般不是以继承的关系来实现的,而是通常使用组合关系来复用父加载器的代码。

简单总结一下双亲委派模型的执行流程:

  • 在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载(每个父类加载器都会走一遍这个流程)。
  • 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 loadClass()方法来加载类)。这样的话,所有的请求最终都会传送到顶层的启动类加载器 BootstrapClassLoader 中。
  • 只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载(调用自己的 findClass() 方法来加载类)。

打破双亲委派

双亲委派机制实现向上委派是通过调用父加载器 loadClass()方法来加载类来实现的。所以要打破我们就可以重写该方法来实现。

Tomcat 服务器为了能够优先加载 Web 应用目录下的类,然后再加载其他目录下的类,就自定义了类加载器 WebAppClassLoader 来打破双亲委托机制。这也是 Tomcat 下 Web 应用之间的类实现隔离的具体原理。

著作权归所有 原文链接:javaguide.cn/java/jvm/cl…
《对线面试官》Java编译到执行的过程 (qq.com)
CS-Notes/Java 虚拟机.md at master · CyC2018/CS-Notes (github.com)