专栏首页chenchenchen类加载:双亲委派机制

类加载:双亲委派机制

  • 类的生命周期
  • 类加载器
  • 双亲委派机制

类的生命周期

类从被加载到虚拟机开始,到卸载出内存为止,它的整个的生命周期包括:加载、连接(验证、准备、解析)、初始化、使用和卸载七个阶段

加载过程

将编译之后的Class文件加载至虚拟机,并存储在方法区。

连接过程

连接被分为了验证、准备、解析三部分。

验证:Class文件中的信息是否符合Java虚拟机的要求,是否安全(可能会做出危害虚拟机的行为)。

准备:为类变量分配内存,并设置类变量的初始值。不包含实例变量的内存,实例变量的内存将会被分配到堆中。

这里的初始值指的是数据类型的零值,并非程序员设置的值,比如static int i = 1;此时得到的i是0,赋值为1将会在初始化阶段执行。

解析:将常量池中的符号引用替换为直接引用(内存地址)。

a.run();代码表示对A类的run()方法的符号引用,由run()方法的全名 和 相关描述符组成。 解析阶段,Java虚拟机会把这个符号引用替换为一个指针,该指针指向A类的run()方法在方法区的内存位置,这个指针就是直接引用

初始化

前面的类加载过程中,除了通过自定义类加载器参与之外,其余的动作其实都是由虚拟机主导和控制的。

初始化是类加载的最后一步,真正开始执行程序中代码的步骤,比如将i赋值为1的过程,初始化类变量,加载类的静态语句块的过程。

在准备阶段赋值过一次了,那次赋值是系统要求的初始值,跟我们个人的设定无关,而初始化的赋值才是真正根据程序员设计而主导的初始化

使用和卸载

使用类的阶段就是new对象的过程,我们会使用到各种类型对象,以及使用完毕对这个类型的卸载,卸载一般发生在程序关闭的时候。

程序正常执行结束、遇到异常关闭、或者操作系统出问题导致程序关闭这些都会卸载这些类的加载。

类加载器

从JVM的角度看,类加载器主要有两类:

  • Bootstrap ClassLoader和其他类加载,Bootstrap ClassLoader是C++语言实现,是虚拟机自身的一部分;
  • 其他类加载器都是Java语言实现,不属于虚拟机,全部继承自抽象类java.lang.ClassLoader

从Java开发者的角度看,需要了解类加载器的双亲委派模型,如下图所示:

启动类加载器Bootstrap ClassLoader

这个类加载器将负责存放在/lib目录中,并且是虚拟机会识别的jar类库加载到内存中。更直白点说,就是我们常用的java.lang开头的那些类,一定是被Bootstrap ClassLoader加载的

扩展类加载器Extension ClassLoader

它负责加载/lib/ext目录中的、或者被java.ext.dirs系统变量指定的路径中的所有类库。

应用程序类加载器Application ClassLoader

它负责加载用户CLASSPATH环境变量指定的路径中的所有类库。如果应用程序中没有自定义过自己的类加载器,这个就是一个Java程序中默认的类加载器。

用户自定义的类加载器

用户在需要的情况下,可以实现自己的自定义类加载器,一般而言,在以下几种情况下需要自定义类加载器

  • 隔离加载类。某些框架为了实现中间件和应用程序的模块的隔离,就需要中间件和应用程序使用不同的类加载器
  • 修改类加载的方式。类加载的双亲委派模型并不是强制的,用户可以根据需要在某个时间点动态加载类
  • 扩展类加载源,例如从数据库、网络进行类加载
  • 防止源代码泄露。Java代码很容易被反编译和篡改,为了防止源码泄露,可以对类的字节码文件进行加密,并编写自定义的类加载器来加载自己的应用程序的类

双亲委派机制

向上委托,向下加载

如果一个类加载器收到了类加载的请求,不考虑们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有就把请求委托给父加载器去完成,依次向上。

因此,所有的类加载请求最终都被传递到顶层的启动类加载器BootstrapClassLoader。这时候开始考虑自己是否能加载了,如果在它的搜索范围中没有找到所需的类时,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException。

源码

“java.lang”包下的ClassLoader类中loadClass方法代码如下:

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}
//              -----??-----
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
        // 首先,检查是否已经被类加载器加载过
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            try {
                // 存在父加载器,递归的交由父加载器
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    // 直到最上面的Bootstrap类加载器
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }
 
            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                c = findClass(name);
            }
        }
        return c;
}

双亲委派机制的作用

1、避免类的重复加载。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。

2、保护程序安全,保证核心类不能被篡改。通过委托方式,不会去篡改核心.class,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

  • 自定义类:java.lang.String (没用)
  • 自定义类:java.lang.ShkStart(报错:阻止创建 java.lang开头的类)

为了系统类的安全,类似java.lang.String这种,jvm需要保证 Java 应用所使用的都是同一个版本的 Java 核心库的类,是互相兼容的。系统的类已经被Bootstrap classLoader加载过了,所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

如果我们有一个类想要通过自定义的类加载器来加载,可以通过重写ClassLoader中的loadClass方法,实现自定义类加载器。改变类的类加载器的时候要注意,如果全部改了,找不到Object.class这种顶级类,就加载不了了。

参考:

通俗易懂的双亲委派机制:https://blog.csdn.net/codeyanbao/article/details/82875064

Java 符号引用 与 直接引用:https://www.cnblogs.com/mzzcy/p/7223405.html

如何破坏双亲委派:https://mp.weixin.qq.com/s/k0_K627ENyHeE92vW5HIiw

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android类加载之双亲委派机制

    我们定义一个CustomClassLoader加载器,去加载String.class文件的流程如下:

    码农帮派
  • [五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的

    本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的

    noteless
  • 深入探究JVM之类加载与双亲委派机制

    前面学习了虚拟机的内存结构、对象的分配和创建,但对象所对应的类是怎么加载到虚拟机中来的呢?加载过程中需要做些什么?什么是双亲委派机制以及为什么要打破双亲委派机制...

    夜勿语
  • 谈谈类加载器的双亲委派机制

    负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

    葆宁
  • Java虚拟机类加载器及双亲委派机制

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    程序新视界
  • JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

    其中最核心的方法 loadClass ,其实现我们常说的双亲委派机制 ,我们后面展开。

    小小工匠
  • JVM学习笔记(二)类加载器及双亲委派机制

    glm233
  • jvm类加载机制,双亲委派机制,看这一篇就够了

    今天我们来讲讲jvm里类加载的过程,我们写了那么多类,却不知道类的加载过程,岂不是很尴尬。

    公众号 IT老哥
  • Java 类加载机制及双亲委派模型

    即 加载 → \rightar...

    Steve Wang
  • JVM类加载机制和双亲委派模型

    虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。

    用户3467126
  • 类加载器与双亲委派模型1 类加载器 2 双亲委派模型

    类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因。 在类加载的第一阶段“加载”过程中,需要通过一个类的全限定名来获取...

    JavaEdge
  • Java虚拟机:类加载机制与双亲委派模型

    .java文件中的代码在编译后,就会生成JVM能够识别的二进制字节流class文件,class文件中描述的各种信息,都需要加载到虚拟机中才能被运行和使用。

    全栈程序员站长
  • 双亲委派机制

    孙晨c
  • Java虚拟机的类加载机制及双亲委派模型

    所谓双亲委派就是类加载器在加载一个类的时候会先委托它的父类尝试去加载,父类又会委托父类尝试去加载。如果父类加载不了子类再自己加载,这样可以保证相同类型的类他们的...

    诺浅
  • Java的类加载器种类(双亲委派)

    1.启动类加载器:这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的类库。...

    爱撸猫的杰
  • 类加载过程,双亲委派模型?

    java通过字节码和JVM机制,提供了强大的跨平台能力,理解Java的类加载机制能让我们更加了解java的运行过程

    居士
  • JVM - 双亲委派机制

    父加载器不是“类加载器的父类加载器”!!! 双亲委派是一个孩子向父亲(上级)方向,然后父亲向孩子方向的双亲委派过程

    Parker
  • 类加载器以及双亲委派模型

    首先我们来描述一个小说场景,通过这个场景在去理解我们相关的类加载器的执行以及双亲委派模型。

    胖虎
  • 一、类加载的双亲委托机制详解

        在父亲委托机制中,各个加载器按照父子关系形成了树形结构,除了根类加载器之外,其余类加载器都有且只有一个父加载器

    梅花

扫码关注云+社区

领取腾讯云代金券