当前位置: 首页 > 网络应用技术

两个父母任命机制的详细分析和原则

时间:2023-03-07 21:39:07 网络应用技术

  之前写过:为什么要研究装载过程?为什么研究双边父母任命机制?

  研究班的过程是要知道,在加载班级时,使用两个父母的任命机制。但是只知道双边任命机制不是目的。目的是了解为什么使用两个父母的任命机制。他的原则是什么?知道两个父母任命机制的逻辑思想,然后我们是否可以使用这个想法并将其用于我。这是学习知识的目的。

  例如:两个父母的约会机制避免重复班级的加载,并避免被核心库修改。我们可以从两个父母的任命机制中学习。

  另一个例子,实现了两个父母任命机制的责任链设计模式。我们可以研究责任链设计模式,以便理解任命原则。因此,我们可以使用哪些场景使用负责任的链设计模式?更多地思考学习的目的和本质。

  您学到的可以在工作中使用的是国王。

  让我们首先看一个案例:打印目录加载程序,扩展加载程序和应用程序类加载程序的目录

  让我们来看看:

  指导类加载的文件是:启动器。getBootstrapClassPath()。

  扩展加载程序加载的文件为:Java.ext.dirs,Java扩展目录目录

  应用程序类加载程序,加载:Java.class.Path,Java Home Path

  让我们看一下印刷结果

  .8.0_181.jdk/contents/lib/jce.jar file:/library/javavalmua(javavalmuavalmjdk1.8.0_181.0/contents/contsents/home/jre/jre/jre/lib/charsets.jar文件:/library/java/java/java/java/java/javava/javavairalmmacachnes/jdk1.0.0.0_181.jdk/home/lib/jfr.jar:java/javavirtualmachines/jdk1.8.0_181.jdk/home/home/jre/classe

  /扩展:/系统/库/Java/Extensions:/usr/lib/java

  _181.jdk/contents/home/jre/lib/ext/jfxrt.jar:/library/java/javavirtuachines/jdk1.8.8.0.jdk/home/home/home/lib/lib/lib/lib/lib/libext/liblext ext/lib /lib /li /li /li /li /li /li /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib /lib/jdk 11.8.8.8.8.8.8.0.8home/tar/tar/lb/jfr.jar:/lii三/java/javavirtualmacolutions/8.8.0_181.jdk/conents/e/e/e/lib/lib/java/lib/java/libava/libaviralmachichichichichichichichichichichichichichichichichichichine/8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8。8.8JDK1.8.8JDK1.1.8JDK1.1.8JDK1.1.8JDK1.1.1.1.8JDK1.1.1.8JDK1.1.1.8JDK1.8JDK1.8./HOME/LIB/LIB/SA-JDI.JALjdk/contents/lib/tools.jar:/users/dospace/project/project/talll/tarll/tarll/urs/rig/rig/springfrit/serit/spring-tarts/2.2.2.2.2.2.2.2.2.2.con-2.2.2.2.2.2.2.28ttring-tartrter-2.2.2.2.2.2.2.2.2.2.2.2 e.2.2.2.2.2.2.glicue/rg/tarboot/2.2.8.release/spring-boot- 2.2.8.release.jar:/users/Responsitority/org/springframework/spring/spring-release/spring-5.2.7。repares.jar:/users/Responsitory/org/springframework/spring-re/5.2.7.release/spring-5.2.7.release.jar.jar:/users/Responsitority/Springframework/springframework/spring-bean/spring-beans/5.2.7.2.7.releasease/.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8-Starter-Logging-2.2.8.Release.jar:/users/undersitory/ch/qos/logback/logback- classic/1.2.3/logback-classic 1.2.3.3.jar:/users/users/consewmity/ch/qos qos qos qos qos/logback/logback- core/1.2.3/logback-core-1.2.3.3.jar:/users/Responsitory/org/apache/logging/log4j/log4j/log4j/2.12.12.1/log4j-slf4j-2.12.1.1.jar:/users/Responsitory/org/apache/logging/log4j/log4j-di/2.12.1/log4j-di-2.12.12.1.jar:/users/org/org/slf4j/jul-to-slf4j/1.7.7.7.30/to-slf4j-1.7.7.7.30.jar:/usponsitory/jakarta/annotation/jakarta.annotation-api/1.3.5/jakarta.annotation-antotation-di-1.3.5.5.jar:/users/responsitority/Responsitority/Responsitory/org/springframework/springframework/springframework/spring-core/5.2.7.Release/spring-core-5.2.7.release.jar:/users/Responsitory/org/springframework/spring-jcl/5.2.7.release/spring-jcl-5.2.7.rease.jar.jar:/USPOSTIRE/SNAKEYAML/1.25/SNAKEYAML-1.25.JA:用户/响应/org/slf4j/slf4j/slf4j-api/1.7.30/slf4j-api-1.7.30.jar:Jar:

  /applications/inellij indue.app/contents/lib/idea_rt.jar

  通过观察,我们发现

  指导类加载程序仅在Java Home下的/jre/lib目录下加载类

  扩展装载机将类加载到Java扩展目录中

  但是,应用程序类加载程序,加载的类包含java Home下的/jre/lib目录,Java Home Extension中的类以及响应仓库下的类,以及IDEA类别以及我们的课堂课程路径下的目标。

  问题出现了,为什么AppClassLoader加载器加载指南加载程序和扩展加载程序想要加载的类?不是重复吗?

  实际上,它不会重复加载。AppClassloader加载的类是目标目录中的类。其他目录中的类不会加载。为什么?这是因为双边任命机制。

  上图是两个父母任命机制的图片。这也是集体加载的原则。总共两个部分:

  以自定义java.lxl.jvm.math类为例。让我们看一下该类是如何由类加载程序加载的。

  步骤1:首先,要查找java.lxl.jvm.math class.math class.math class.math class.math class.this clast。但是它并未由应用程序类加载程序。。

  步骤2:扩展类加载程序还首先搜索,以查看是否有已加载的java.lxl.jvm.math。如果有的话,如果没有,则将加载此类。加载时,它不是由他自己加载的,而是要委托他的父亲班来指导装载机加载。

  步骤3:Guidance Class Loader首先发现是否有已加载的类。如果有的话,请返回。这次,我们都知道数学课是由我自己定义的。不可能拥有指导类加载程序。负载失败,因此他将加载此类。返回扫描/lib/jar软件包。/lib/jar软件包中是否有任何此类类,并确定扩展加载程序已加载。扩展加载程序将扫描扩展程序包lib/jar/ext。

  [通过分析,我们可以得出结论,使用了两个父母任命机制的负责任链设计模型。

  然后,这里有一个问题,也就是说,应用程序类加载程序首先加载,然后最终返回到应用程序类加载程序。经过一个圆圈之后,它会多一点,周期是两次?为什么我必须从应用程序类加载器加载?直接从指导类加载器加载不好?只有一个周期...

  实际上,对于我们的项目,该类的95%是由我们自己编写的,因此我们写的课程是有应用程序类加载器加载。实际上,应用程序类加载程序只是时间的第一个时间,它将被加载两次。将来,当再次使用此类时,请直接询问应用程序类加载程序。有这堂课吗?已经存在,它将直接返回。

  C ++语言仍然从这张图片中调用Sun.misc.launcher.getLauncher()获取启动器对象。当启动器类初始化其构造函数创建ExtClassLoader和AppClassLoader。然后调用启动器对象的getClassLoader()方法。

  getClassLoader()返回this.loader对象。启动器初始化时分配了加载程序对象。LoadClass是AppClassloader。

  类加载程序如何加载类?

  调用了loader.loadClass(“ com.lxl.math”)方法。让我们看一下ClassLoader Loader.Acording到上述分析,我们知道,当启动器类初始化时,LoadClass是AppClassLoader。

  让我们看一下源代码。我们使用断点进行分析。

  首先,我们在Launcher的AppClassLoader的LoadClass(String var1,boolean var2)方法中添加了一个断点,并将其分配给我们的com.lxl.jvm.math类

  然后运行数学的主要方法,让我们看一下该类是如何加载的

  启动调试调试模式,首先输入启动.appClassLoader.loadClass(....)方法

  让我们仔细研究一下此方法的实现

  以上是所有权限验证。我们查看关键代码:

  从注释部分看,我们知道这是双边任命机制的第一步。现在可以在AppClassloader中找到它。从已加载的类中,它将直接返回。如果找不到,请加载此类。我们以两个步骤查看这两个步骤:部分是FindloaderClass()的源代码,另一部分是Super.loadClass(...)的源代码。

  步骤1:在加载类中,找出是否使用FindloaderClass(VAR1)来确定缓存之前的nown.uc.ucp.nownotexist(var1)。如果有的话,请致电this.findloadClass(var1);find.findloadClass最终称为本地方法来查找本地方法

  步骤2:我以前从未加载此类别。第一次加载了第一个负载,即super.loadclass(var1,var2),这是谁?让我们看一下AppClassloader之间的综合关系

  按选项+命令+u在Mac上查看集成关系图

  我们看到AppClassLoader从URLCLASSLOADER继承,URLCLASSLOADER继承了上述四个类。最后,有一个名为ClassLoader的类。所有类加载程序最终都必须继承此类Loader类。

  这是super.loadClass()。让我们看一下UrlClassloader中是否有LoadClass()类。阅读后,他发现他没有,最终这个super.loadclass()是LoadClass(... ... ....)方法

  正是这个班级实现了双边任命机制。让我们看一下他如何实现呢?

  当前类加载程序是AppClassLoader类加载程序。首先,第一步是找到已在AppClassloader中加载的类。有这个课吗?我们看到这里有支票。

  通过调用已加载的类中的FindloadedClass(名称)方法,没有com.lxl.jvm.math类。那么,您在FindloadedClass(名称)中做了什么?让我们进去看看

  我们看到FindloaderClass(名称)方法调用其自己的方法FindloadClass0。该方法是本地方法,即本地方法。它由C ++实现。我们看不到底部的特定实现详细信息。在已加载的类中找到。没有com.lxl.jvm.math。如果有的话,请返回类信息。

  Debug看到这显然是没有,下一步是IF(C == NULL)。你在这里做了什么?

  他判断当前的装载机的父母是否为无效。我们知道当前类带有AppClassloader。他的父母是ExtClassLoader,自然不是null,因此您将执行parent.loadClass(name,false);

  也就是说,执行扩展加载程序的负载频率(...)方法。让我们看一下Extension ExtClassLoader

  我们发现ExtClassloader类中没有LoadClass(...)方法,然后他不这样做,必须在父类中定义它。通过搜索,我们发现该方法仍然是ClassLoader中的LoadClass(...)方法。我们继续进行调试。我们一定会再次进入LoadClass(...)方法。目前,LoadClass是ExtClassloader的LoadClass(...)方法。

  果然,我又来了这个方法

  继续执行,首先查找已在ExtClassloader中加载的类。有java.lxl.jvm.math课程。该过程与上面相同。最后一个呼叫是本地方法。

  我们知道这一定是否。然后继续判断ExtClassLoader的父母是否为空。显然,他是空的,因为ExtClassloader的母体加载程序是指导加载程序BootstrapClassLoader,并且导向加载程序为C ++。写入,因此这里的lar是空的。父是对代码的空执行

  此方法是在指南Loader BootstrapClassload中找到,以查找是否有此类

  我们发现,最后的特定逻辑也是通过本地方法实现的。我们仍然猜测,这是找到指导类已加载的类。

  显然,没有。c == null。我们继续查看下面的以下代码

  到目前为止,第一次查找的过程已经完成。这就是我们使用的。

  首先,有一个应用程序类加载程序加载类,以确定该类中是否有加载应用程序的类。如果没有,则没有办法调用父母加载程序ExtClassLoader的LoadClass()方法,从而有此类,没有。然后确定父类是否为空,确实是空的,然后输入指导类加载程序以查找此类的搜索,最后是指导类加载程序没有

  让我们看一下如何向下分配的类加载程序?

  指南类加载程序中没有这样的类。回到null。返回空心包含两个步骤。一个是找到它。另一个是未找到后在/lib/jar目录下加载此类。EssenceFinally返回null。

  接下来,致电FindClass(名称);查找ExtClassloader中是否有com.lxl.jvm.math,让我们看一下特定的实现。这是谁?它是ExtClassLoader。

  输入FindClass(名称)方法,首先查看ExtClassLoader类中是否有此方法。不,这是父级UrlClassloader中的FindClass()方法

  在findClass()中,我们看到路径中的路径..类,这是路径

  然后转到资源库查找此路径。如果您不这样做,请返回null。如果有的话,请输入deciteClass()方法。

  让我们考虑一下,您可以在ExtClassLoader路径中找到此类吗?显然,找不到这个课程,因为此课程使我们自己定义它。

  他们必须执行返回null。

  当我们分析时,Debug到达了RETURN NULL;此时,通过执行执行ExtClassLoader的FindClass()。

  C为null,然后继续执行FindClass(名称)。此时

  如上所示,此时,称为AppClassloader的FindClass(名称)。此时资源仍然空吗?当然,目标目录中有一个Math.lass类,找到它,然后执行确定性(name,res)。

  DefindClass的方法是什么?此方法是加载类。已经找到了班级。接下来要做的就是加载它。

  类DefindClass()的四个步骤此类执行加载过程。线圈。

  看这四个步骤:

  内部的核心逻辑代码是本地方法。我们可以看到的是一些基本验证,例如准备阶段,分析阶段和初始化阶段是本地方法

  可以理解这件代码。无需在-Depth中学习。

  以上是两个父母任命机制的源代码。

  然后,当我们遇到com.lxl.jvm.math类时,我们已经在AppClassloader中有直接返回。

  再次查看两个父母的任命机制的流程图

  两个原因:

  1.沙盒安全机制,Java.lang.String.Class类,不会加载,这可以防止核心API库随意进行修改。

  2.避免重复加载类,例如我之前所说的,在AppClassloader中的Java/jre/lib软件包下有一个类。他会加载吗?加载后,直接返回以避免重复加载。

  让我们看以下情况

  如果我在本地定义字符串类,则软件包名称为java.lang.string。

  如上所示,这是我们运行主要方法的方式,将会发生什么?是的,我将报告一个错误

  让我们分析,为什么要报告错误?

  仍然查看双边约会机制的过程,首先由AppClassLoader类加载程序加载,以查看是否有已加载的Java.lang.string类。它...结果,您找不到主要方法。

  因此,如果我们自己定义它,我们想重新定义系统加载的类,例如字符串。

  这是双边任命机制的第一个角色:沙盒安全机制,java.lang.string.kass class我写的阶级不会被加载,因此可以防止随意修改核心API库。

  两个父母的任命机制也有一个好处:避免重复加载类。例如,我之前说过的是,当AppClassloader中的AppClassloader下面有一个类时,当上述类加载器加载时,它直接返回以避免重复加载。

  第三个角色:全面的佣金机制。例如,数学类定义了私人用户;然后,用户也将由AppClassLoader加载。除非它是指定使用其他类加载程序来加载的。