2.jvm类加载系统

目录

  • 概述
  • 类加载器
    • 执行顺序
    • 加载时机与过程
      • 类加载的四个时机
      • 一个类的一生
    • 类加载途径
  • 自定义类加载器
    • 工作准备
    • 编写自定义加载器
    • 结果
  • 结束

概述

类加载器

jvm 的类加载是通过 ClassLoader 及其子类来完成的。
有以下类加载器

注意: bootstrap 引导程序

2.jvm类加载系统_第1张图片

根据上图总结如下

  • 启动类加载器(Bootstrap ClassLoader):负责加载 JAVA_HOME\lib 目录或通过 -Xbootclasspath 参数指定路径中的且被虚拟机认可(rt.jar) 的类库。
  • 扩展类加载器(Extension ClassLoader):负责加载 JAVA_HOME\lib\ext 目录或者通过 java.ext.dirs 系统变量指定路径中的类库。
  • 应用程序类加载器(Application ClassLoader):负责加载用户路径 classpath 上的类库 (自己编写的程序在此加载)
  • 自定义类加载器(User ClassLoader):加载应用之外的类文件 (例如:JRebel 热部署)

执行顺序

来看一下图:
2.jvm类加载系统_第2张图片

  1. 检查顺序是自底向上: 加载过程中会先检查类是否被已加载,从 Custom 到 BootStrap 逐层检查,只要某个类加载器已加载就视为此类已加载,**好处:**保证此类所有 ClassLoader 只加载一次。
  2. 加载的顺序是自顶向下: 也就是由上层来逐层尝试加载此类。

加载时机与过程

类加载的四个时机

public class Student{
	private static int age;
	public static void method(){
	}
}

// Student.age
// Student.method();
// new Student();
Class t = Class.forName("java.lang.Thread")
  • 遇到 new、getStatic、putStatic、invokeStatic 四条指令时
  • 使用 java.lang.reflect 包方法时,对类进行反射调用
  • 初始化一个类时,发现其父类还没初始化,要先初始化其父类
  • 当虚拟机启动时,用户需要指定一个主类 main,需要先将主类加载

一个类的一生

当一个 .java 文件被编译成 class 文件
类的生命周,而非对象的生命周期,看下图
2.jvm类加载系统_第3张图片

类加载主要做了三件事:

  • 1.根据 类全限定名称,二进制字节流加载 class 文件
  • 2.字节流静态数据 ,进入方法区 (永久代、元空间)
  • 3.创建字节码 Class 对象

类加载途径

2.jvm类加载系统_第4张图片

加载途径总结如下:

  • 1.jar/war
  • 2.jsp生成的 class
  • 3.数据库中的二进制字节流
  • 4.网络中的二进制字节流
  • 5.动态代理生成的二进制字节流

自定义类加载器

工作准备

准备好需要加载的类,代码很简单

package com.fun.demo;

public class Test {
    public void say() {
        System.out.println("hello jvm");
    }
}

编译完成后放置如下路径: /Users/hyl/Desktop/jk/jvm/lib/com/fun/demo
在这里插入图片描述

编写自定义加载器

自定义类加载器 CustomClassLoader 继承 ClassLoader ;重写 findClass()方法,在findClass方法中调用 defineClass() 方法

自定义加载器如下,代码还是很简单的。

package com.fun.classloader;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class CustomClassLoader extends ClassLoader {

    private String rootPath;

    public CustomClassLoader(String rootPath) {
        this.rootPath = rootPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // name 传进来的全类名称
        String absolutePath = rootPath + "/" + name.replace(".", "/") + ".class";
        try {
            FileInputStream in = new FileInputStream(absolutePath);
            byte[] classByte = in.readAllBytes();
            return defineClass(null, classByte, 0, classByte.length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException exception) {
            exception.printStackTrace();
        }
        return null;
    }
}

测试代码如下:

package com.fun.classloader;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

public class Test {
    //public static void main(String[] args) {
    //    String tmp = "com.fun.demo.Test";
    //    System.out.println(tmp.replace(".", "/"));
    //}

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        CustomClassLoader loader = new CustomClassLoader("/Users/hyl/Desktop/jk/jvm/lib");
        Class<?> clz = loader.loadClass("com.fun.demo.Test");
        if (Objects.nonNull(clz)) {
            Object o = clz.newInstance();
            Method method = clz.getMethod("say", null);
            method.invoke(o, null);
        }
    }
}

结果

运行 main 方法,得到的效果如下:
2.jvm类加载系统_第5张图片

结束

至此,jvm 类加载系统就结束了,如有疑问,欢迎评论区留言。

你可能感兴趣的:(jvm,jvm,类加载系统,类加载器,自定义类加载器)