别再乱看教程了!从源码剖析JVM类加载机制,打通双亲委派机制!

简介: 别再乱看教程了!从源码剖析JVM类加载机制,打通双亲委派机制!

万丈高楼平地起。大家入门JAVA必然绕不开JVM的研究,在保证基础知识储备的同时,把面试的火箭顺手造了岂不是美滋滋。

aa6e5f07d689e1325c73475d0f79f837.gif


干货概要

  • 搞通类加载器,自己动手做类加载器!
  • 为啥有双亲委派机制?
  • 如何打破双亲委派机制及其应用?


1 搞通类加载器

方便理解晦涩原理,先来一波简单实例代码开开胃。

package TaorenCoding
public class Math {
  public static final int initData = 666;
  public static User user = new User();
 public int compute() { //一个方法对应一块栈帧内存区域
   int a = 1;
   int b = 2;
   int c = (a + b) * 10;
   return c;
 }
 public static void main(String[] args) {
   Math math = new Math();
   math.compute();
 } }


如上代码,看的懂吧,够清晰吧。好了那接下来就是真正的硬菜。

584a8d6c5a783be724118639693ba05c.png

扒拉出其中的核心要点:类加载过程

其中loadClass的类加载过程有如下几步:

加载 : 在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等等,在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

验证 : 校验字节码文件的正确性(如魔数等二进制内容)

准备 :给类的静态变量分配内存,并赋予默认值

解析 :将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用

初始化: 对类的静态变量初始化为指定的值,执行静态代码块

使用

卸载


自定义类加载器

自定义类加载器只需要继承 java.lang.ClassLoader 类,该类有两个核心方法,一个是 loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空方法,所以我们自定义类加载器主要是重写findClass方法。


直接继承方法开造!

1 public class MyClassLoaderTest {
2   static class MyClassLoader extends ClassLoader {
3   private String classPath;
4
5   public MyClassLoader(String classPath) {
6     this.classPath = classPath;
7   }
8
9   private byte[] loadByte(String name) throws Exception {
10     name = name.replaceAll("\\.", "/");
11     FileInputStream fis = new FileInputStream(classPath + "/" + name+ ".class");
13     int len = fis.available();
14     byte[] data = new byte[len];
15     fis.read(data);
16     fis.close();
17     return data;
18 }
19
20 protected Class<?> findClass(String name) throws ClassNotFoundException {
21     try {
22       byte[] data = loadByte(name);
23     //defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节
数组。
24     return defineClass(name, data, 0, data.length);
25     } catch (Exception e) {
26       e.printStackTrace();
27       throw new ClassNotFoundException();
28   }
29   }
31 }
32
33 public static void main(String args[]) throws Exception {
34     //初始化自定义类加载器,会先初始化父类ClassLoader,其中会把自定      //义类加载器的父加载器设置为应用程序类加载器AppClassLoader
35   MyClassLoader classLoader = new MyClassLoader("D:/test");
36 //D盘创建 test/com/tuling/jvm 几级目录,将User类的复制类User1.class丢入该目录
37   Class clazz = classLoader.loadClass("com.tuling.jvm.User1");
38   Object obj = clazz.newInstance();
39   Method method = clazz.getDeclaredMethod("sout", null);
40   method.invoke(obj, null);
41   System.out.println(clazz.getClassLoader().getClass().getName());
42   }
43 }
**运行结果:**
 =======自己的加载器加载类调用方法=======
 com.taoren.jvm.MyClassLoaderTest$MyClassLoader


双亲委派机制

为啥要使用双亲委派机制?

  • 沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心API库被随意篡改
  • 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性


打破双亲委派机制

Tomcat作为一个经典的web容器,我们经常用来部署多个实例。有没有想过,我们所部署的多个应用时不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求同一个类库在同一个服务器只有一份,因此要保证每个应用程序的类库都是独立的,保证相互隔离,由此,Tomcat是打破双亲委派机制的典型应用。主要原因如下:


部署在同一个web容器中相同的类库相同的版本可以共享。否则,如果服务器有10个应用程序,那么要有10份相同的类库加载进虚拟机。

web容器也有自己依赖的类库,不能与应用程序的类库混淆。基于安全考虑,应该让容器的类库和程序的类库隔离开来。

web容器要支持jsp的修改,我们知道,jsp 文件最终也是要编译成class文件才能在虚拟机中运行,但程序运行后修改jsp已经是司空见惯的事情, web容器需要支持 jsp 修改后不用重启。

a3ea9858b6949d5e6aebd2cbda874cbd.gif

相关文章
|
1月前
|
安全 前端开发 Java
JDK源码级别彻底剖析JVM类加载机制
JDK源码级别彻底剖析JVM类加载机制
|
21天前
|
存储 缓存 Java
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
金石原创 |【JVM盲点补漏系列】「并发编程的难题和挑战」深入理解JMM及JVM内存模型知识体系机制(1)
34 1
|
4月前
|
前端开发 JavaScript 算法
尚硅谷JVM全套教程
尚硅谷JVM全套教程
|
5月前
|
算法 数据可视化 Java
深入理解JVM系列教程(完) - 终章总结
深入理解JVM系列教程(完) - 终章总结
35 0
|
5月前
|
Java 编译器
深入理解JVM系列教程(12) - 热部署
深入理解JVM系列教程(12) - 热部署
54 0
|
3天前
|
监控 Java 关系型数据库
JVM工作原理与实战(十三):打破双亲委派机制-线程上下文类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了打破双亲委派机制的方法、线程上下文类加载器等内容。
|
1月前
|
前端开发 Java
深入理解Java虚拟机:类加载机制
【2月更文挑战第23天】本文深入探讨了Java虚拟机(JVM)的类加载机制,包括类加载器的层次结构、类加载的过程以及双亲委派模型。通过对JVM类加载机制的理解,可以帮助我们编写更高效的Java代码。
|
1月前
|
安全 前端开发 Java
【JVM】双亲委派机制详细解读(通俗易懂)
【JVM】双亲委派机制详细解读(通俗易懂)
81 0
|
2月前
|
安全 Java 应用服务中间件
|
3月前
|
缓存 安全 前端开发
JVM(类的加载与ClassLoader、双亲委派机制)
JVM(类的加载与ClassLoader、双亲委派机制)