【jvm】01-双亲委派都会说,破坏双亲委派你会吗

欢迎关注b站账号/公众号【六边形战士夏宁】,一个要把各项指标拉满的男人。该文章已在github目录收录。

屏幕前的大帅比大漂亮如果有帮助到你的话请顺手点个赞、加个收藏这对我真的很重要。别下次一定了,都不关注上哪下次一定。

1.类的生命周期

首先可以从图中明确类的生命周期

1)遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始 化,则需要先触发其初始化阶段。能够生成这四条指令的典型Java代码场景有: ·使用new关键字实例化对象的时候。 ·读取或设置一个类型的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外) 的时候。·调用一个类型的静态方法的时候。

2)使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需 要先触发其初始化。

3)当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先 初始化这个主类。

5)当使用JDK 7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解 析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句 柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。

6)当一个接口中定义了JDK 8新加入的默认方法(被default关键字修饰的接口方法)时,如果有 这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

  1. 验证

1)通过一个类的全限定名来获取定义此类的二进制字节流。

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

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

  1. 加载

1)文件格式验证

2)元数据验证

3)字节码验证

4)符号引用验证

  1. 准备

    为静态变量分配内存并设置类变量初始值(null)

    注意这里有个概念为方法区,是逻辑概念

    jdk8以前使用永久代实现方法区(有专门的永久代区域),在后面使用了元空间实现方法区,但实例变量物理存储地址其实是放到了堆中。所以说静态变量、字符串等存在堆中也对,存在方法区也对。

  2. 解析

    解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符这7

    类符号引用进行,分别对应于常量池的CONSTANT_Class_info、CON-STANT_Fieldref_info、

    CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、

    CONSTANT_MethodType_info、CONSTANT_MethodHandle_info、CONSTANT_Dyna-mic_info和 CONSTANT_InvokeDynamic_info 8种常量类型。

    主要有以下4种解析过程。

    1)类或接口的解析

    2)字段解析

    3)方法解析

    4)接口方法解析

  3. 初始化

  4. 使用

  5. 卸载

2.jdk8双亲委派模型

双亲委派核心代码package sun.misc.Launcher;

  1. public Class<?> loadClass(String var1, boolean var2) throws ClassNotFoundException {
  2. int var3 = var1.lastIndexOf(46);
  3. if (var3 != -1) {
  4. SecurityManager var4 = System.getSecurityManager();
  5. if (var4 != null) {
  6. var4.checkPackageAccess(var1.substring(0, var3));
  7. }
  8. }
  9. if (this.ucp.knownToNotExist(var1)) {
  10. Class var5 = this.findLoadedClass(var1);
  11. if (var5 != null) {
  12. if (var2) {
  13. this.resolveClass(var5);
  14. }
  15. return var5;
  16. } else {
  17. throw new ClassNotFoundException(var1);
  18. }
  19. } else {
  20. return super.loadClass(var1, var2);
  21. }
  22. }
  1. // 演示的时候漏了一段核心代码 先是一层一层往上抛,如果父加载器找不到则自己加载
  2. protected Class<?> loadClass(String name, boolean resolve)
  3. throws ClassNotFoundException
  4. {
  5. synchronized (getClassLoadingLock(name)) {
  6. // 检查当前类加载器是否已经加载了该类
  7. Class<?> c = findLoadedClass(name);
  8. if (c == null) {
  9. long t0 = System.nanoTime();
  10. try {
  11. if (parent != null) { //如果当前加载器父加载器不为空则委托父加载器加载该类
  12. c = parent.loadClass(name, false);
  13. } else { //如果当前加载器父加载器为空则委托引导类加载器加载该类
  14. c = findBootstrapClassOrNull(name);
  15. }
  16. } catch (ClassNotFoundException e) {
  17. // ClassNotFoundException thrown if class not found
  18. // from the non-null parent class loader
  19. }
  20. if (c == null) {
  21. // If still not found, then invoke findClass in order
  22. // to find the class.
  23. long t1 = System.nanoTime();
  24. //都会调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类
  25. c = findClass(name);
  26. // this is the defining class loader; record the stats
  27. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  28. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  29. sun.misc.PerfCounter.getFindClasses().increment();
  30. }
  31. }
  32. if (resolve) { //不会执行
  33. resolveClass(c);
  34. }
  35. return c;
  36. }
  37. }

从代码和图中可知所谓双亲委派就是一层一层往上找,每层加载的代码不同避免了重复加载,通常用户所写的代码在系统类加载器

演示代码

  1. package com.example.demo.lesson.jvm.loader;
  2. import sun.misc.Launcher;
  3. import java.net.URL;
  4. public class ClassLoaderExe {
  5. public static void main(String[] args) {
  6. // 核心rt.jar中的类加载器 是C++加载的,因此这里为null
  7. System.out.println(String.class.getClassLoader());
  8. // 扩展包的加载器 ExtClassLoader
  9. System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader());
  10. // 应用加载器 AppClassLoader
  11. System.out.println(ClassLoaderExe.class.getClassLoader());
  12. System.out.println("");
  13. // 获取系统ClassLoader
  14. ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
  15. // appClassLoader的父加载器
  16. ClassLoader extClassLoader = appClassLoader.getParent();
  17. // extClassLoader的父加载器
  18. ClassLoader boostrapClassLoader = extClassLoader.getParent();
  19. System.out.println("the bootstrapLoader : " + boostrapClassLoader);
  20. System.out.println("the extClassloader : " + extClassLoader);
  21. System.out.println("the appClassLoader : "+ appClassLoader);
  22. System.out.println("==============bootstrapLoader加载的文件====================");
  23. URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
  24. for (int i = 0; i < urLs.length; i++) {
  25. System.out.println(urLs[i]);
  26. }
  27. System.out.println("");
  28. System.out.println("==============extClassloader加载的文件====================");
  29. System.out.println(System.getProperty("java.ext.dirs"));
  30. System.out.println("");
  31. System.out.println("==============appClassLoader 加载的文件====================");
  32. System.out.println(System.getProperty("java.class.path"));
  33. }
  34. }

3.jdk9破坏双亲委派模型

核心代码在jdk11进行了迁移jdk.internal.loader.ClassLoaders

  1. private static final BootClassLoader BOOT_LOADER;
  2. private static final PlatformClassLoader PLATFORM_LOADER;
  3. private static final AppClassLoader APP_LOADER;
  4. // Creates the built-in class loaders.
  5. static {
  6. // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
  7. String append = VM.getSavedProperty("jdk.boot.class.path.append");
  8. BOOT_LOADER =
  9. new BootClassLoader((append != null && !append.isEmpty())
  10. ? new URLClassPath(append, true)
  11. : null);
  12. PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
  13. // A class path is required when no initial module is specified.
  14. // In this case the class path defaults to "", meaning the current
  15. // working directory. When an initial module is specified, on the
  16. // contrary, we drop this historic interpretation of the empty
  17. // string and instead treat it as unspecified.
  18. String cp = System.getProperty("java.class.path");
  19. if (cp == null || cp.isEmpty()) {
  20. String initialModuleName = System.getProperty("jdk.module.main");
  21. cp = (initialModuleName == null) ? "" : null;
  22. }
  23. URLClassPath ucp = new URLClassPath(cp, false);
  24. APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
  25. }

从图和代码中可知在java模块化后通过判断该模块由哪个类加载器加载就直接加载不用再一层层往上找

演示代码

  1. package com.example.demo.lesson.jvm.loader;
  2. import java.net.URL;
  3. public class ClassLoaderPlant {
  4. public static void main(String[] args) {
  5. System.out.println(String.class.getClassLoader());
  6. System.out.println(ClassLoaderPlant.class.getClassLoader());
  7. System.out.println("");
  8. // 获取系统ClassLoader
  9. ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
  10. // appClassLoader的父加载器
  11. ClassLoader platformClassLoader = appClassLoader.getParent();
  12. // platformClassLoader的父加载器
  13. ClassLoader boostrapClassLoader = platformClassLoader.getParent();
  14. System.out.println("the bootstrapLoader : " + boostrapClassLoader);
  15. System.out.println("the extClassLoader : "+ platformClassLoader);
  16. System.out.println("the appClassLoader : "+ appClassLoader);
  17. }
  18. }

参考资料

《深入理解Java虚拟机》-周志明

# 【jvm】01-双亲委派都会说,破坏双亲委派你会吗的更多相关文章

  1. Tomcat类加载器破坏双亲委派

    转载:https://blog.csdn.net/qq_38182963/article/details/78660779 http://www.cnblogs.com/aspirant/p/8991 ...

  2. 【JVM】浅谈双亲委派和破坏双亲委派

    一.前言 笔者曾经阅读过周志明的<深入理解Java虚拟机>这本书,阅读完后自以为对jvm有了一定的了解,然而当真正碰到问题的时候,才发现自己读的有多粗糙,也体会到只有实践才能加深理解,正应 ...

  3. JDBC、Tomcat为什么要破坏双亲委派模型?

    问题一:双亲委派模型是什么 如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的 ...

  4. 破坏双亲委托机制的一些情况---Tomcat和JDBC,破坏后的安全问题

    采用双亲委托机制的原因 类加载器就是将字节码搬进jvm方法区的组件.我们知道,JVM识别加载进来的类是通过类加载器+类全名完成的,也就是说同一个类由不同类加载器加载进去的话就会被视为不同的类.jdk提 ...

  5. jdbc 加载数据库驱动如何破坏双亲委托模式

    导读      通过jdbc链接数据库,是每个学习Java web 方向的人必然一开始会写的代码,虽然现在各路框架都帮大家封装好了jdbc,但是研究一下jdbc链接的套路还是很意义     术语以及相 ...

  6. ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制

    ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...

  7. JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制

    代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...

  8. 深入理解JVM(一)类加载器部分:双亲委派模型

    类加载器的父亲委托机制 在父亲委托机制中,各个类加载器按照父子关系形成了树形结构,除了根类加载器之外,其余的类加载器都有且只有一个父加载器. 先让最顶层可以加在的父加载器加栽(所有可加载的加载器中,处 ...

  9. JVM—01

    目录 1.1 JVM系统架构图 2.1 类加载器 2.1.1 双亲委派机制 2.1.2 沙箱安全机制 3.1 Native 4.1 PC寄存器 1.1 JVM系统架构图 JVM是什么? JVM是Jav ...

随机推荐

  1. 一起手写吧!Promise!

    1.Promise 的声明 首先呢,promise肯定是一个类,我们就用class来声明. 由于new Promise((resolve, reject)=>{}),所以传入一个参数(函数),秘 ...

  2. CVTE第二次笔试

    选择瞎答得,直接编程题目 1. 使用递归将字符串中的数字去并按顺序打印 输入例  adfsafsfs123123eogie09789 输出例 123123 09789 #include<iost ...

  3. Nested Classes in C++

    A nested class is a class which is declared in another enclosing class. A nested class is a member a ...

  4. SpringMVC(3):AJAX

    一,AJAX 简介 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML) AJAX 不是新的编程语言,而是一种使用现有标准的新方法 ...

  5. react中在hooks方法useEffect中加载异步数据

    useEffect( ()=>{ (async function getPipeList(value:any) { let result= await GetPipeList(value); s ...

  6. 使用cookie记录用户上次访问网页的时间,并返回到页面

    package com.hopetesting.cookie;import javax.servlet.ServletException;import javax.servlet.annotation ...

  7. 从orderby引发的SQL注入问题的思考

    背景: 某一天准备上线,合完master之后准备发布了,忽然公司的代码安全监测提示了可能在代码中存在sql注入的风险,遂即检查,发现sql注入问题 既然碰到了这个问题,那就了简单了解下sql注入 基础 ...

  8. .net core Winform 添加DI和读取配置、添加log

    首先新建配置类 public class CaptureOption { /// <summary> /// 是否自启 /// </summary> public bool A ...

  9. SOUI3界面编辑器使用说明

    SOUI一直没有官方的界面编辑器,关键是我自己一直坚持手写界面更好控制. 大概是2年前,网友"指尖"开发了一个SOUI2的编辑器,功能非常多,特点是可以拖动控件来实现可视化布局. ...

  10. Nginx编译添加新模块

    目录 一.简介与思路 一.简介与思路 当前适用于nginx已经在安装过了,如果没安装过,直接在编译时候添加模块即可. Nginx主要程序就是nginx这个二进制脚本,只要在编译一个nginx脚本替换掉 ...