从JDK源码级别剖析JVM类加载机制

类加载运行的全过程

当用java命令运行某个main函数时,首先需要类加载器把主类加载到JVM内存中。

通过Java命令执行代码的大致流程为

 

 将编译好的字节码class文件通过java命令,在win操作系统就是一个java.exe文件,这个文件底层是c++语言实现的,通过这个文件调用底层jvm.dll文件创建Java虚拟机,这个jvm.dll文件也是c++语言实现的就是一些类库。在创建JVM虚拟机的过程中会通过c++语言创建一个引导类加载器。最终由C++语言调用java代码创建JVM启动器Launcher,该类由引导类加载器创建其他类加载器,最终调用的Launcher类的getLauncher()方法,这个方法创建加载了扩展类加载器,应用程序类加载器。最终调用loadClass()方法实现类的加载,这个方法体现了双亲委派机制。

java里面有一下几种类加载器:

引导类加载器:加载jre/lib下核心jar包 如rt.jar charset.jar

扩展类加载器:加载jre/lib/ext下面的jar包

应用程序类加载器:加载自己写的java类

自定义类加载器:负责加载用户自定义路径下的类包

如果想要摆脱双亲委派机制可以重写loadclass方法

//ClassLoader的loadClass方法,里面实现了双亲委派机制
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 }
2021 if (c == null) {
22 // If still not found, then invoke findClass in order
23 // to find the class.
24 long t1 = System.nanoTime();
25 //都会调用URLClassLoader的findClass方法在加载器的类路径里查找并加载该类
26 c = findClass(name);
27
28 // this is the defining class loader; record the stats
29 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 ‐ t0);
30 sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
31 sun.misc.PerfCounter.getFindClasses().increment();
32 }
33 }
34 if (resolve) { //不会执行
35 resolveClass(c);
36 }
37 return c;
38 }
39 }

如果想自己定义类加载器,定义要加载自己的类路径则重新编写findClass()方法;

为什么jdk设计者要对类加载实现双亲委派机制?

1.沙箱安全机制 自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改 
2.避免类的重复加载 父类加载过得类,子类没必要重复加载

 

posted @ 2020-06-30 22:51  喜欢喵喵的花花  阅读(120)  评论(0编辑  收藏  举报