• 回顾一下类加载过程
  • 类加载器总结
  • 双亲委派模型
    • 双亲委派模型介绍
    • 双亲委派模型实现源码分析
    • 双亲委派模型的好处
    • 如果我们不想要双亲委派模型怎么办?
  • 自定义类加载器
  • 推荐

回顾一下类加载过程

类加载过程:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析。

一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 loadClass() 方法)。数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。

所有的类都由类加载器加载,加载的作用就是将 .class文件加载到内存。

类加载器总结

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader

  1. BootstrapClassLoader(启动类加载器) :最顶层的加载类,由C++实现,负责加载 %JAVA_HOME%/lib目录下的jar包和类或者或被 -Xbootclasspath参数指定的路径中的所有类。
  2. ExtensionClassLoader(扩展类加载器) :主要负责加载目录 %JRE_HOME%/lib/ext 目录下的jar包和类,或被 java.ext.dirs 系统变量所指定的路径下的jar包。
  3. AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用classpath下的所有jar包和类。

双亲委派模型

双亲委派模型介绍

每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 双亲委派模型 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。**加载的时候,首先会把该请求委派该父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader中。当父类加载器无法处理时,才由自己来处理。**当父类加载器为null时,会使用启动类加载器 BootstrapClassLoader 作为父类加载器。

每个类加载都有一个父类加载器,我们通过下面的程序来验证。

public class ClassLoaderDemo {
public static void main(String[] args) {
System.out.println("ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader());
System.out.println("The Parent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent());
System.out.println("The GrandParent of ClassLodarDemo's ClassLoader is " + ClassLoaderDemo.class.getClassLoader().getParent().getParent());
}
}

Output

ClassLodarDemo's ClassLoader is sun.misc.Launcher$AppClassLoader@18b4aac2
The Parent of ClassLodarDemo's ClassLoader is sun.misc.Launcher$ExtClassLoader@1b6d3586
The GrandParent of ClassLodarDemo's ClassLoader is null

AppClassLoader的父类加载器为ExtClassLoader ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 Bootstrap ClassLoader 。

其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mather ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方API文档对这部分的描述如下:

The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.

双亲委派模型实现源码分析

双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在 java.lang.ClassLoader 的 loadClass() 中,相关代码如下所示。

private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先,检查请求的类是否已经被加载过
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {//父加载器不为空,调用父加载器loadClass()方法处理
c = parent.loadClass(name, false);
} else {//父加载器为空,使用启动类加载器 BootstrapClassLoader 加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//抛出异常说明父类加载器无法完成加载请求
} if (c == null) {
long t1 = System.nanoTime();
//自己尝试加载
c = findClass(name); // this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}

双亲委派模型的好处

双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果不用没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类。

如果我们不想用双亲委派模型怎么办?

为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重载 loadClass() 即可。

自定义类加载器

除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader

推荐阅读

五、JVM — 类加载器的更多相关文章

  1. 深入JVM类加载器机制,值得你收藏

    先来一道题,试试水平 public static void main(String[] args) { ClassLoader c1 = ClassloaderStudy.class.getClass ...

  2. JVM类加载器的分类

    类加载器的分类 JVM支持两种类型的类加载器,分别为引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-Defined ClassLoader). 从概念上来讲,自定 ...

  3. (二十七)JVM类加载器机制与类加载过程

    一.Java虚拟机启动.加载类过程分析 下面我将定义一个非常简单的java程序并运行它,来逐步分析java虚拟机启动的过程. package org.luanlouis.jvm.load; impor ...

  4. jvm类加载器以及双亲委派

    首先来了解几个概念: 类加载: 概念:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验--转换解析--初始化,最终形成能被java虚拟机直接使用的java类型,就是jvm的类加载机制. ...

  5. JVM 类加载器 (二)

    1.类加载器(ClassLoader)负责加载class文件,class文件在文件开头有特定的文件标识,并且ClassLoader只负责 class 文件的加载,至于class文件是否能够运行则由Ex ...

  6. JVM类加载器及Java类的生命周期

    预定义类加载器(三种): 启动(Bootstrap)类加载器: 是用本地代码实现的类装入器,它负责将<Java_Runtime_Home>/lib下面的类库加载到内存中(比如rt.jar) ...

  7. JVM类加载器工作流程

    类加载器 classloader:谈到类加载,不得不提的就是负责此项工作的类加载器classloader,classloader的职责是将Java源文件编译后的字节码文件加载到内存中去执行. 类加载至 ...

  8. A3. JVM 类加载器

    [概述] 虚拟机设计团队把类加载阶段中的 “通过一个类的全限定名来获取描述此类的二进制字节流” 这个动作放到 Java 虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码 ...

  9. 彻底搞懂JVM类加载器:基本概念

    本文阅读时间大约9分钟. 写在前面 在Java面试中,在考察完项目经验.基础技术后,我会根据候选人的特点进行知识深度的考察,如果候选人简历上有写JVM(Java虚拟机)相关的东西,那么我常常会问一些J ...

随机推荐

  1. profile 配置文件修改后如何生效?

    1.profile生效命令 . /etc/profile 或 source /etc/profile 说明:source命令也称为“点命令”,也就是一个点符号(.)

  2. 实战build-react(二)-------引入Ant Design

    安装 Ant Design  npm install antd --save 或 yarn add antd 注释:https://www.jianshu.com/p/21caf40ee93e(cop ...

  3. BZOJ 4289: PA2012 Tax Dijkstra + 查分

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...

  4. JavaWeb学习篇之----浏览器缓存问题详解

    摘要 1.Etag和Expires中Client 端Http Request Header及Server端Http Reponse Header工作原理. 2.静态下Apache.Lighttpd和N ...

  5. Comparable接口与Comparator接口的比较————Comparator接口详解

    Comparator接口位于:java.util包中. Comparator接口:1. 强行对某个对象的Collection进行整体排序.值得注意的是:Comparator接口可以作为参数传到一些so ...

  6. ORACLE sqlprompt设置

    SYS@orcl>defineDEFINE _DATE           = "17-JUN-19" (CHAR)DEFINE _CONNECT_IDENTIFIER = ...

  7. node服务通过Jenkins上线流程

    构建流程 构建服务器: 拉取指定分支代码 构建服务器: 安装依赖 构建服务器: 执行构建 构建服务器: 如果上线流程,则在 git 上创建 tag,供回滚使用 构建服务器:打包 node 服务代码,和 ...

  8. 二、Python基础

    1.变量名 数字,字母,下划线:aaa1;aa_b1 不能以数字开头:1aa 变量名不能是python内部的关键字 2.getpass import getpass username=raw_inpu ...

  9. Windows程序调用dll

    可以写在WndProc的WM_CREATE里面,不能写在WinMain里面

  10. 【命令汇总】XSS payload 速查表

    日期:2019-05-15 14:06:21 作者:Bay0net 介绍:收集并且可用的一些 XSS payload,网上的速查表很多,但是测试了下很多 payload 的不可用,这里都是自己能用的 ...