精华内容
下载资源
问答
  • 主要介绍了java 详解类加载器的双亲委派及打破双亲委派的相关资料,需要的朋友可以参考下
  • java类加载机制主要包括:加载—>验证—>准备—>解析—>初始化—>使用—>卸载,而类加载器的作用主要发生在加载阶段。 加载阶段,类加载器主要做了但不限于如下三件事: 1、通过一个的全限定...

    一、类加载器

    java类加载机制主要包括:加载—>验证—>准备—>解析—>初始化—>使用—>卸载,而类加载器的作用主要发生在加载阶段。

    加载阶段,类加载器主要做了但不限于如下三件事:

    1、通过一个类的全限定名获取这个类的二进制字节流。

    2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

    3、在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的访问入口。

    因为每一个类加载器,都拥有一个独立的类名称空间,所以一个类的唯一性由加载它的类加载器和这个类的本身决定(一个类由类的全限定名和一个类加载器的实例ID作为唯一标识)。比较两个类是否相等(包括Class对象的equals()、isAssignableFrom()、isInstance()以及instanceof关键字等),只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,这两个类就必定不相等。

    JVM中提供了三层的ClassLoader:

     其实还有一个类加载器,就是用户自定义类加载器,CustomClassLoader

    二、双亲委派机制

    如果有一个我们写的Hello.java编译成的Hello.class文件,它是如何被加载到JVM中的呢?别着急,请继续往下看。

    1、源码分析

      打开“java.lang”包下的ClassLoader类,然后将代码翻到loadClass方法:

    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
            synchronized (getClassLoadingLock(name)) {
                // 首先检查这个classsh是否已经加载过了
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
                    try {
                        // c==null表示没有加载,如果有父类的加载器则让父类加载器加载
                        if (parent != null) {
                            c = parent.loadClass(name, false);
                        } else {
                            //如果父类的加载器为空 则说明递归到bootStrapClassloader了
                            //bootStrapClassloader比较特殊无法通过get获取
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {}
                    if (c == null) {
                        //如果bootstrapClassLoader 仍然没有加载过,则递归回来,尝试自己去加载class
                        long t1 = System.nanoTime();
                        c = findClass(name);
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }

    其实这段代码已经很好的解释了双亲委派机制,下面这张图来描述一下上面这段代码的流程:

    从上图中我们就更容易理解了,当一个Hello.class这样的文件要被加载时。

    1、不考虑我们自定义类加载器,首先会在AppClassLoader中检查是否加载过,如果有那就无需再加载了。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。

    2、父类中同理也会先检查自己是否已经加载过,如果没有再往上。

      注意这个类似递归的过程,直到到达Bootstrap classLoader之前,都是在检查是否加载过,并不会选择自己去加载。

    3、直到BootstrapClassLoader,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层。

    4、如果没有任何加载器能加载,就会抛出ClassNotFoundException

    5、“父委派模型”是怎么工作的?

      举个例子,当前有个Test.class,需要加载rt.jar中的java.lang.String,那么加载的流程如下图所示,整体的加载流程是向上委托父加载器完成的。

      如果整个链路中,父加载器都没有加载这个类,且无法加载这个类时,才会由Test.class所在的加载器去加载某个类(例如希望加载开发人员自定义的类 Test2.class)。

     三、为什么要设计这种机制

    这种设计有个好处是,如果有人想替换系统级别的类:String.java,篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了(为什么?因为当一个类需要加载的时候,最先去尝试加载的就是BootstrapClassLoader),所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。

    “父委派模型”保证了系统级别的类的安全性,使一些基础类不会受到开发人员“定制化”的破坏。

    如果没有使用父委派模型,而是由各个类加载器自行加载的话,如果开发人员自己编写了一个称为java.lang.String的类,并放在程序的ClassPath中,那系统将会出现多个不同的String类, Java类型体系中最基础的行为就无法保证。应用程序也将会变得一片混乱。

      双亲委派机制的作用:

    1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
    2、保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

     四、代码示例

    package java.lang;
    
    public class String {
        static{
            System.out.println("我是自定义的String类的静态代码块");
        }
    }

    在另外的程序中加载 String 类,看看加载的 String 类是 JDK 自带的 String 类,还是我们自己编写的 String 类

    public class StringTest {
    
        public static void main(String[] args) {
            java.lang.String str = new java.lang.String();
            System.out.println("hello,atguigu.com");
    
            StringTest test = new StringTest();
            System.out.println(test.getClass().getClassLoader());
        }
    }

    程序并没有输出我们静态代码块中的内容,可见仍然加载的是 JDK 自带的 String 类

      为什么呢?由于我们定义的String类本应用系统类加载器,但它并不会自己先加载,而是把这个请求委托给父类的加载器去执行,到了扩展类加载器发现String类不归自己管,再委托给父类加载器(引导类加载器),这时发现是java.lang包,这事就归引导类加载器管,所以加载的是 JDK 自带的 String 类

    2、举例 2 :

      在我们自己的 String 类中整个 main() 方法

    package java.lang;
    
    public class String {
        static{
            System.out.println("我是自定义的String类的静态代码块");
        }
        //错误: 在类 java.lang.String 中找不到 main 方法
        public static void main(String[] args) {
            System.out.println("hello,String");
        }
    }

    由于双亲委派机制找到的是 JDK 自带的 String 类,但在引导类加载器的核心类库API里的 String 类中并没有 main() 方法

    3、举例 3:

      在 java.lang 包下整个 ShkStart 类 (自定义类名)

    package java.lang;
    
    public class ShkStart {
        public static void main(String[] args) {
            System.out.println("hello!");
        }
    }

    会报错,出于保护机制,java.lang 包下不允许我们自定义类

      通过上面的例子,我们可以知道,双亲机制可以

    (1)避免类的重复加载

    (2)保护程序安全,防止核心API被随意篡改

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

     

    展开全文
  • Java 类加载双亲委派机制 在讲“双亲委派机制”前,首先讲一讲类加载器的关系。如果对类加载还不太熟悉的话,也可以直接到我之前转载的一篇关于类加载的文章,戳我。 类加载器: 我们定义下的,如果我们...

    Java 类加载:双亲委派机制

    在讲“双亲委派机制”前,首先要讲一讲类和类加载器的关系。如果对类加载还不太熟悉的话,也可以直接到我之前转载的一篇关于类加载的文章,戳我

    类加载器:
    我们定义下的类,如果我们要使用这个类,首先就是要把“.java”这个文件便以成class文件,然后由对应的“类加载器”加载到JVM中,我们才能使用这个类对象。
    一般情况下,类的记载是在启动程序时有JVM来完成的,但是某些场景需要我们自己手动去指定加载某个类,这个时候就要用到Class.forName(String className)记载/找到这个className对应的类。

    类记载器类型:

    1. Bootstrap Class Loader: 这是JDK自带的一款类加载器,用于加载JDK内部的类,用来加载$JAVA_HOME/jre/lib下面的那些类
    2. Extension Class Loader:这个主要是加载JDK扩展包里的类,一般是在$JAVA_HOME/lib/ext下面的包中的类
    3. Application Class Loader: 用于记载开发人员中自己平时写的应用代码的类的,加载存放在classpath路径下的哪些应用程序级别的类的
      在这里插入图片描述

    双亲委派机制?
    在oracle的官方翁文档中,对于这个委派机制是这么描述的:

    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平台使用委托模型来加载类。基本思想是每个类加载器都有一个“父”类加载器。在加载类时,类加载器首先将对类的搜索“委托”到其父类加载器,然后再尝试查找类本身。

    下面两幅图为正确以及错误的理解:
    错误理解:在这里插入图片描述
    正确理解:
    在这里插入图片描述
    所以正确的名称应该为父委派模型

    “父委派模型”是怎么工作的?
    例如,我们写了一个测试类Test.class,我们需要加载java.lang.String,那么加载流程如下所示:都是向上委托父类加载器去完成的。
    在这里插入图片描述

    父委派模型的好处
    父委派机制的好处是保证了系统类别的类的安全性,是一些基础类不受开发人员定制化的破坏。,就例如Java.lang.String这个类基本上所有使用Java的都知道,那么如果没有父委派模型,而是由各个类加载器自行加载的话,那么如果我编写一个名称为java.lang.String的类的话,并放在程序中的Classpath中,那么系统中就会出现多个String类,那么到时候究竟要加载哪一个,应用程序也会变得一片混乱。

    什么时候父委派模型是失效的?
    1.通过预加载的方式
    2.通过Thread.getContextClassLoader();

    怎么打破双亲委派机制
    自己写一个类加载器。继承CLoader类并重写loadclass方法和findclass方法

    关于Tomcat的类加载机制:
    Tomcat的类加载机制并不遵循父委派模型。下图是Tomcat类加载器的结构:、
    在这里插入图片描述
    从图中的委派关系中可以看出:

    1.CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用。
    2.CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离。
    3.WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。
    4.JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

    Tomcat违背了父委派模型
    tomcat违背了父委派模型,因为双亲代理机制也就是父委派模型要求除了顶层启动类加载器之外,其余的类加载都应该由其父类加载器加载。而Tomcat不是这样实现的,Tomcat为了实现隔离性,没有遵循这个约定,每个WebappCLoader加载自己目录下的class文件,不会传递给父类加载器

    展开全文
  • JDK8及之前的三层类加载器: 启动类加载器:负责加载<JAVA_HOME>/lib目录下的,或者-Xbootclasspath参数指定的目录下的,并且只有JVM能够识别的类库才会被加载。...默认情况下的默认类加载器就是它,当然

    JDK8及之前的三层类加载器:

    • 启动类加载器:负责加载<JAVA_HOME>/lib目录下的类,或者-Xbootclasspath参数指定的目录下的类,并且只有JVM能够识别的类库才会被加载。
    • 扩展类加载器:负责加载<JAVA_HOME>/lib/ext目录下的类,或者系统变量java.ext.dirs指定的目录下的类。这样用户就可以将通用的类库放入ext目录以扩展Java功能。
    • 应用程序类加载器:负责加载用户ClassPath上的所有的类库。默认情况下的默认类加载器就是它,当然用户也可以自己定义的类加载器。

    类加载器双亲委派模型:

    类加载双亲委派模型

    双亲委派模型工作流程:当收到类加载请求时会首先把请求委托给父类进行加载,每一层都是如此,直到请求传达到最顶层的类加载器,因此所有类加载请求都会到达最顶层的启动类加载器;当父类没有完成类加载请求时,才会自己加载。(请求逐级向上委托,失败逐级向下传递)

    Created with Raphaël 2.2.0 开始 存在父类加载器? 委托父类进行加载 加载成功? 结束 自己进行加载 直接调用顶层类加载器进行加载 yes no yes no

    双亲委派模型实现

    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) {//有父类,则直接委托给父类进行加载
                            c = parent.loadClass(name, false);
                        } else {//没有父类,说明此类加载器是顶层的类加载器,那么就直接调用C++实现的native方法加载该类
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                    }
    
                    if (c == null) {//父类加载器没有成功加载该类,此时才会自己加载
                        long t1 = System.nanoTime();
                        c = findClass(name);
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    
    展开全文
  • 类加载机制,执行顺序如下: 1.装载:查找和导入或接口的二进制数据;...双亲委派机制:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的...

    类加载机制,执行顺序如下:

    1.装载:查找和导入类或接口的二进制数据;

    2.链接:(1)检验:检查导入类或接口的二进制数据的正确性;

                     (2)准备:给类的静态变量分配并初始化存储空间;

                      (3)解析(可略):将符号引用转成直接引用;

    3.初始化:激活类的静态变量的初始化Java代码和静态Java代码块。

    双亲委派机制:当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

    类加载器从上到下为:BootstrapClassLoader(启动类加载器)、ExtClassLoader (标准扩展类加载器)、AppClassLoader(系统类加载器)、CustomClassLoader(用户自定义类加载器)。

    双亲委派机制的作用:

    (1)防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。

    (2)保证核心.class不能被篡改,这样保证了Class执行安全。               

    展开全文
  • 文章目录类加载器一、预定义类型类加载器二、类加载器结构双亲委派模型一、双亲委派模型流程二、双亲委派模型源码自定义类加载器一、类加载器继承关系二、ClassLoader1、构造函数2、核心方法三、自定义类加载器实例...
  • 为什么类加载要使用双亲委派模式来设计?类加载类加载器的类型类加载器和双亲委派模式的关系 类加载器 jvm中,确定一个的唯一性是依赖于加载这个类加载器和这个本身的。只有加载类类加载器和...
  • Java类加载器与双亲委派模式的详解

    千次阅读 2018-08-03 10:04:20
    类加载器(ClassLoader)是Java语言的一项创新,也是Java流行的一个重要原因。在类加载的第一阶段“加载”过程中,需要通过一个的全限定名来获取定义此类的二进制字节流,完成这个动作的代码块就是类加载器。这一...
  •   类加载机制指的是:虚拟机将描述的数据从class文件加载到内存中,对加载的数据进行验证,解析,初始化,最后得到虚拟机认可后转化为直接可以使用java类型的过程   类加载机制一共有七个阶段:加载,验证,...
  • 前言之前详细介绍了Java类的整个加载过程(类加载机制详解)。虽然,篇幅较长,但是也不要被内容吓到了,其实每个阶段都可以一句话来概括。1)加载:查找并加载类的二进制字节流数据。2)验证:保证被加载的正确性...
  • 从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载...
  • 相信不少的同学在面试的时候会被问到一个词:双亲委派,懂得同学懂,不懂的同学可能会尴尬一笑,那么今天咱们就来聊聊这个问题的原理,首先我们需要了解一下java中常见的几种类加载器。 一、Java中常见的类加载器 ...
  • 1.类加载是什么? 将 “.Java” 的文件 转换成 “.class” 的字节码文件 。...是将字节码,从不同的数据源,转化为二进制字节流,加载到内存中,并生成一个代表该java.lang.Class对象。 (2)Verificat..
  • java类加载器以及双亲委派机制 一、类加载器  JVM定义了三类类加载,分别是:  1)Bootstrap ClassLoader /启动类加载器  是本地代码实现的装入器,它负责将$JAVA_HOME中jre/lib/rt.jar下面的类库加载到内存中...
  • 文章对应java8Java类加载器有以下三种:1、启动类加载器(根类加载器Bootstrap ClassLoader)2、扩展类加载器(ExtClassLoader)3、应用类加载器(AppClassLoader)各加载器负责加载:Bootstrap ClassLoader:负责...
  • java程序中的 .java文件编译完会生成 .class文件,而 .class文件就是通过被称为类加载器的ClassLoader加载的,而ClassLoder在加载过程中会使用双亲委派机制”来加载 .class文件,先上图:看着图从上往下介绍:...
  • 类加载器5.1概述5.2类加载器的种类5.3类加载机制5.3.1双亲委派(父类委托)5.3.2 双亲委派的优点5.2.3 为什么打破双亲委派。5.2.4 怎么打破双亲委派:5.2.5 全盘负责机制:5.2.6缓冲机制: Java类加载机制 的...
  • 与一般的编译语言不同,在java语言里面,加载,解析,链接,初始化 等都是在运行时动态进行的,这样虽然有一些性能开销,但是为java语言 提供了很大的灵活性 类加载时机 文件被加载到内存中开始,卸载出内存为...
  • 一、类加载器(Class Loader) ...试想,如果没有双亲委派机制模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名并放在ClassPath中,多个类加载器都会去加载这个到内存中,系统中将
  • java类加载机制 java类加载器ClassLoader是一个抽象,主要是用于将.class文件加载到JVM内存中,并转换成JVM可以识别的Class对象。 ClassLoader结构分析: 经常会或扩展ClassLoader的几个方法及其重载方法...
  • 所谓的类加载器(Class Loader)就是...本篇文章我们重点介绍加载器和双亲委派机制。类加载器在JVM中有三ClassLoader构成:启动(或根)加载器(Bootstrap ClassLoader)、扩展类加载器(ExtClassLoader)、应用类加载...
  • 类加载器ClassLoader: 用于将Java类加载Java虚拟机中,其常用的有...我们之所以安装好java,配置好环境变量,运行起java,就可以直接使用Object obj = new Object(),List list = new ArrayList()之代码,是因
  • 类加载器分为根加载器(bootstrap classloader)、扩展类加载器(ext classloader)、系统类加载器(system classloader)、自定义类加载器(通常继承java.net.URLClassLoader,重写findClass()),它们的关系通常...
  • java类加载机制(这里写自定义目录标题) java类加载机制 四种类加载器 在jvm加载class文件主要由类加载器完成,不同类库下的class加载加载器也不相同,jvm中有以下四种类加载器: boostrapLoader: 引导类加载器: ...
  • 下面有关java classloader说法错误的是? 正确答案: C ...B ClassLoader使用的是双亲委托模型来搜索的 C JVM在判定两个class是否相同时,只用判断类名相同即可,和类加载器无关(错误了...
  • 虚拟机把类加载阶段中“通过一个的权限定名来获取描述此类的二进制字节流”这个动作放到虚拟机外部去实现,以便让程序自己决定如何去获取所需要的。实现这个动作的代码模块称为“类加载器”。
  • Java 类加载的过程和双亲委派机制

    千次阅读 2018-09-28 23:56:43
    1. 类加载机制的层次结构 加载加载阶段会在内存中生成一个代表该的Class对象,作为访问方法...在Java堆中生成一个代表这个java.lang.Class对象,作为对方法区中这些数据的访问入口。 注意:虚拟机规范...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 34,892
精华内容 13,956
关键字:

java类加载要用双亲委派

java 订阅