《从JDK源码级别彻底剖析JVM类加载机制》

一、概念解释

      1、JVM类加载:将.java文件编译成.class文件,加载类将.class文件加载到jvm内存的过程。             加载过程分为:加载、验证、准备、解析、初始化;             加载:就是jvm类加载;             验证:验证二进制的.class文件的是否符合jvm的规范;             准备:静态变量赋初始化值并分配内存;  如: static int a =0; static String name =null(这步赋值根据类型默认值);             解析:将符号引用替换为直接引用,该阶段会把静态方法在内存中通过指针的方式分配内存(直接引用 ),所谓的静态连接,在类加载过程中执行;还有一些被调用的方法,会在运行时何时用到何时进行加载分配内存地址,这些是所谓的动态连接;            初始化:对类的静态变量进行实际赋值,并且执行静态代码块; 如:static int a =666; static String name ="hello word";            类被加载到方法区中后主要包含:运行时常量区,类型信息,方法信息,字段信息,类加载的引用,对应class的实例;         《从JDK源码级别彻底剖析JVM类加载机制》       2、类加载机制              双亲委派机制:由父加载器加载类,如果加载不到由子加载器加载(父加载和子加载不是父子关系,是上下级关系);如下图:              引导类加载器(BootStrapClassLaoder): 加载jdk核心类库,jdk/jre/lib/rt.jar 等等;              扩展类加载器  (ExtClassLaoder): 加载jdk/jre/lib/ext/.jar 等等;              应用类加载器  (AppClassLoader): 加载程序员自己写的类, ClassPath路径下的类; 《从JDK源码级别彻底剖析JVM类加载机制》  3、为什么要用双亲委派机制?                 沙箱安全机制:JDK是java最核心的类库,也是java开发必需环境,如果随便就可以更改,随便一个黑客就可以写同一个类比如:String类等等, 那么JDK早已沦陷;                 避免重复加载相同包名称下的相同类;   二、源码双亲委派机制  3、为什么要用双亲委派机制?                 沙箱安全机制:JDK是java最核心的类库,也是java开发必需环境,如果随便就可以更改,随便一个黑客就可以写同一个类比如:String类等等, 那么JDK早已沦陷;                 避免重复加载相同包名称下的相同类;   二、源码双亲委派机制        1、由c++实现引用启动类,然后调用Launcher类中的getLauncher()方法创建单例Launcher对象 ; 《从JDK源码级别彻底剖析JVM类加载机制》 2、new Launcher()对象调用Launcher构造方法,创建ExtClassLaoder与AppClassLoader类加载器,并且把ClassLoader赋值为AppClassLoader类加载器; 《从JDK源码级别彻底剖析JVM类加载机制》 3、this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);跳进getAppClassLoader(var1)进入AppClassLoader类调用loadClass()方法最终调用父类的loadClass()父类为:Classloader类中loadClass()方法执行双亲外派机制; 《从JDK源码级别彻底剖析JVM类加载机制》《从JDK源码级别彻底剖析JVM类加载机制》《从JDK源码级别彻底剖析JVM类加载机制》注上图:当前是AppClassLoader加载器,Class<?> c = findLoadedClass(name);首先判断要加载类是否已载,如果是直接返回,如果否,就获取当前加载器的parent是ExtClassLoader加载器去加载,如果没有,再次获取ExtClassLoader加载器的parent,因为引用类加载器BootStrapClassLoader加载器是c++编写的,java语言是无法获取的,参数值为null,所以parent为null,)所以执行c = findBootstrapClassOrNull(name);方法《从JDK源码级别彻底剖析JVM类加载机制》(注上图:当c 变量为空,这是就是执行if代码块中的代码,最终如果父加载器都没有加载成功,就会调用当前加载器AppClassLoader加载器的findClass(name )方法) 《从JDK源码级别彻底剖析JVM类加载机制》 (注上图:因为AppClassLoader加载器没有重写findClass()方法,所以调用父类URLClassLoader类的findClass()方法,获取classPath路径的类,进行加载,最后调用defineClass()方法进行执行验证、准备、解析、初始化)   三、实现自定义加载器       1、实现自定义加载器其实很简单,我们分析加载器最重要的就是通过双亲委派机制来实现,那么这个机制的源码实现ClassLoader类中loadClass方法,所以我们只要自定义类然后继承ClassLoader类就可以了;       2、当然自定义加载器肯定要加载咱们自定义路径下的类,通过双亲委派机制的源码我们很清楚的知道,URLClassLoader类下的findClass()方法加载了ClassPath路径的类,所以我们只要重写这个方法,让我们加载器去获取我们自定义的路径类就可以了(注:自定义加载器的父加载器是应用加载器(appClassLoader)) 《从JDK源码级别彻底剖析JVM类加载机制》 四、打破双亲委派机制       1、其实打破双亲委派机制也不难,我们通过源码分析知道双亲委派机制是在ClassLoader类中loadClass()方法实现的,所以只要重写loadClass()方法,把有关双亲外派机制的逻辑代码去掉就可以了;(特别注意:本人遇到坑,程序员自己写的类,很多时候还是会用到JDK类库的核心类,比方你创建了User类,但是它的父类是Object类,当加载Obj类的时候就会报错,加载不到此类,所以需要加判断,当加载是自己包下的类是去 掉双亲,如果不是还走之前双亲逻辑) 《从JDK源码级别彻底剖析JVM类加载机制》   本人工作3年中级菜鸟程序员, 最近想回顾一下知识,做了一些简单总结同时也为了自己今后复习方便,如果有逻辑错误,大家体谅,同时也希望大牛们能给出正确答案让我改正,谢谢!
上一篇:Java类的加载过程和双亲委派机制


下一篇:java虚拟机详细图解10--JVM类加载机制及类加载过程