JVM学习笔记中篇--再谈类的加载器

文章目录

  • 一、概述
    • 1.类加载的分类
    • 2.类加载器的必要性
    • 3.命名空间
    • 4.类加载机制的基本特征
  • 二、复习:类的加载器分类
    • 1.引导类加载器
    • 2.扩展类加载器
    • 3.系统类加载器
    • 4.用户自定义类加载器
  • 三、测试不同的类加载器
  • 四、ClassLoader源码解析
    • 1.ClassLoader的主要方法
    • 2.SecureClassLoader与URLClassLoader
    • 3.Class.forName()与ClassLoader.loadClass()
  • 五、双亲委派机制
    • 1.定义与本质
    • 2.优势与劣势
    • 3.破坏双亲委派机制
    • 4.热替换的实现
  • 六、沙箱安全机制
  • 七、自定义类的加载器
    • 1.实现方式
  • 八、jdk9新特性


一、概述

JVM学习笔记中篇--再谈类的加载器_第1张图片

1.类加载的分类

JVM学习笔记中篇--再谈类的加载器_第2张图片

2.类加载器的必要性

JVM学习笔记中篇--再谈类的加载器_第3张图片

3.命名空间

JVM学习笔记中篇--再谈类的加载器_第4张图片

4.类加载机制的基本特征

JVM学习笔记中篇--再谈类的加载器_第5张图片

二、复习:类的加载器分类

JVM学习笔记中篇--再谈类的加载器_第6张图片

1.引导类加载器

JVM学习笔记中篇--再谈类的加载器_第7张图片

2.扩展类加载器

JVM学习笔记中篇--再谈类的加载器_第8张图片

3.系统类加载器

JVM学习笔记中篇--再谈类的加载器_第9张图片

4.用户自定义类加载器

JVM学习笔记中篇--再谈类的加载器_第10张图片

三、测试不同的类加载器

JVM学习笔记中篇--再谈类的加载器_第11张图片

四、ClassLoader源码解析

JVM学习笔记中篇--再谈类的加载器_第12张图片

1.ClassLoader的主要方法

  1. loadClass源码解析(满足双亲委派机制的主要逻辑就是在loadClass方法中实现的)

假设测试代码:ClassLoader.getSystemClassLoader.loadClass("com.atguigu.java.User")

涉及到对如下方法的使用
 protected Class<?> loadClass(String name, boolean resolve)//resolve:true-加载class的同时进行解析操作
        throws ClassNotFoundException
    {
     
        synchronized (getClassLoadingLock(name)) {
     //同步操作,保证只能加载一次
            // 首先,在缓存中判断是否已经加载同名的类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
     
                long t0 = System.nanoTime();
                try {
     
                	//获取当前类加载器的父类加载器
                    if (parent != null) {
     
                    	//如果存在父类加载器,则调用父类加载器进行类的加载
                        c = parent.loadClass(name, false);
                    } else {
     //parent为null:父类加载器是引导类加载器
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
     
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
     //当前类的加载器的父类加载器未加载此类 or 当前类的加载器未加载此类
                    //调用当前ClassLoad的findClass()
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
     //是否进行解析操作
                resolveClass(c);
            }
            return c;
        }
    }

2.SecureClassLoader与URLClassLoader

JVM学习笔记中篇--再谈类的加载器_第13张图片

3.Class.forName()与ClassLoader.loadClass()

JVM学习笔记中篇--再谈类的加载器_第14张图片

五、双亲委派机制

1.定义与本质

JVM学习笔记中篇--再谈类的加载器_第15张图片

2.优势与劣势

3.破坏双亲委派机制

  1. 破坏双亲委派机制1
    JVM学习笔记中篇--再谈类的加载器_第16张图片

  2. 破坏双亲委派机制2

  3. 破坏双亲委派机制3
    JVM学习笔记中篇--再谈类的加载器_第17张图片

4.热替换的实现

JVM学习笔记中篇--再谈类的加载器_第18张图片
代码实现热替换案例:
1、先自定类加载器(下面有代码案例)
2、用死循环来模拟在一直运行的程序,每次循环都创建了一个新的类加载器

public class LoopRun {
     

    public static void main(String[] args) throws Exception {
     

       while (true){
     
           MyClassLoader myClassLoader = new MyClassLoader("D:\\代码包\\JVMDemo\\chapter08\\src\\com\\atguigu\\java\\");
           Class clazz = myClassLoader.findClass("Demo1.class");
           Object demo = clazz.newInstance();
           Method method = clazz.getMethod("hot");
           method.invoke(demo);
           Thread.sleep(5000);

       }

    }

}

六、沙箱安全机制

JVM学习笔记中篇--再谈类的加载器_第19张图片

七、自定义类的加载器

JVM学习笔记中篇--再谈类的加载器_第20张图片

1.实现方式

JVM学习笔记中篇--再谈类的加载器_第21张图片

/**
 * 自定义ClassLoader
 *
 * @author xzt
 * @create 2021-01-19 15:28
 */
public class MyClassLoader extends ClassLoader {
     

    private String byteCodePath;//字节码文件的路径

    public MyClassLoader(String path) {
     
        this.byteCodePath = path;
    }

    public MyClassLoader(ClassLoader parent, String byteCodePath) {
     
        super(parent);
        this.byteCodePath = byteCodePath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
     
        //获取字节码文件的完整路径
        String fileName = "";
        if (name.contains(".class")) {
     
            fileName = byteCodePath + name;
        } else {
     
            fileName = byteCodePath + name + ".class";
        }


        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = null;
        int len = -1;
        try {
     
            //获取一个输入流
            bis = new BufferedInputStream(new FileInputStream(fileName));
            //获取一个字节数组输出流
            baos = new ByteArrayOutputStream();

            //具体读入数据并写出数据的过程
            byte[] data = new byte[1024];
            while ((len = bis.read(data)) != -1) {
     
                baos.write(data, 0, len);
            }

            //获取内存中完整的字节数据
            byte[] byteCode = baos.toByteArray();
            //调用defineClass将字节数组的数据转换为Class的实例
            Class clazz = defineClass(null, byteCode,0, byteCode.length);
            return clazz;
        } catch (Exception e) {
     
            e.printStackTrace();
        }finally {
     
            if (baos != null){
     
                try {
     
                    baos.close();
                } catch (IOException e) {
     
                    e.printStackTrace();
                }
            }

            if (bis != null){
     
                try {
     
                    bis.close();
                } catch (IOException e) {
     
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

}

八、jdk9新特性

你可能感兴趣的:(JVM,java,jvm)