【JVM】双亲委派机制、打破双亲委派机制


🐌个人主页: 🐌 叶落闲庭

💨我的专栏:💨
c语言
数据结构
javaEE
操作系统
Redis

石可破也,而不可夺坚;丹可磨也,而不可夺赤。


JVM

  • 一、双亲委派机制
    • [1.1 双亲委派的作用](#1.1 双亲委派的作用)
    • [1.2 什么是双亲委派机制](#1.2 什么是双亲委派机制)
    • [1.3 双亲委派机制问题](#1.3 双亲委派机制问题)
    • [1.4 面试题(类的双亲委派机制是什么)](#1.4 面试题(类的双亲委派机制是什么))
  • 二、打破双亲委派机制
    • [2.1 自定义类加载器](#2.1 自定义类加载器)

一、双亲委派机制

由于)va虚拟机中有多个类加载器,双亲委派机制的核心是解决一个类到底由谁加载的问题。

1.1 双亲委派的作用

  • 保证类加载的安全性:
    • 通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如java.lang.String,确保核心类库的完整性和安全性。
  • 避免重复加载:
    • 双亲委派机制可以避免同一个类被多次加载。

1.2 什么是双亲委派机制

  • 双亲委派机制指的是:当一个类加载器接收到加载类的任务时,会自底向上查找是否加载过,再由顶向下进行加载。


假设在com.practice包下有一个类A.java,应用程序类加载器接收到一个任务,他要去加载A.java这个类,首先他会检查一下这个类有没有被加载过,发现没有被加载过,那么他就会把这个类委派给它的父类(扩展类加载器),扩展类加载器发现也没有加载过,继续向上委派,委派给它的父亲(启动类加载器),启动类加载器发现A.java曾经加载过,所以它直接把A.java类的class对象返回,加载过程结束。

如果所有的父类加载器都无法加载该类,则由当前类加载器自己尝试加载。所以看上去是自顶向下尝试加载。

假设在com.practice包下有一个类B.java,三个类加载器都没有加载过,此时会首先从顶部(启动类加载器)尝试进行加载,发现这个类不在当前类加载器的加载路径当中,就把这个任务委派给它的下级(扩展类记载器),此时刚好有这个类的加载路径,就会进行加载,而当应用类加载器要加载B.java时,首先还是对他的父类进行查找,判断是否加载过,加载过,则返回这个类的class对象
向下委派起到了一个加载优先级的作用

1.3 双亲委派机制问题

  • 重复的类:
    • 如果一个类重复出现在三个类加载器的加载位置,应该由谁来加载?

答案应该是启动类加载器加载,因为根据双亲委派机制,它的优先级是最高的

  • String类能覆盖吗
    • 在自己的项目中去创建一个java.lang.String类,会被加载吗

不能,会返回启动类加载器加载在rt.jar包中的String类

1.4 面试题(类的双亲委派机制是什么)

1、当一个类加载器去加载某个类的时候,会自底向上向父类查找是否加载过,如果加载过就直接返回,如果一直到最顶层的类加载器都没有加载,再由顶向下进行加载。

2、应用程序类加载器的父类加载器是扩展类加载器,扩展类加载器的父类加载器是启动类加载器。

3、双亲委派机制的好处有两点:第一是避免恶意代码替换DK中的核心类库,比如java.lang.String,确保核心类库的完整性和安全性。第二是避免一个类重复地被加载

二、打破双亲委派机制

2.1 自定义类加载器

  • 双亲委派机制的核心代码(源码):
java 复制代码
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    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;
        }
    }
  • 自定义类加载器:
java 复制代码
public class BreakClassLoader1 extends ClassLoader {
    private String basePath;
    private final static String FILE_EXT = ".class";

    public void setBasePath(String basePath) {
        this.basePath = basePath;
    }

    private byte[] loadClassDate(String name) throws IOException {
        String path = basePath + File.separatorChar + name.replace('.', File.separatorChar) + FILE_EXT; // 将包名转换为文件路径
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            is = new FileInputStream(path);
            baos = new ByteArrayOutputStream();
            int bufferSize = 4096;
            byte[] buffer = new byte[bufferSize];
            int bytesNumRead = 0;
            while ((bytesNumRead = is.read(buffer)) != -1) {
                baos.write(buffer, 0, bytesNumRead);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classDate = new byte[0];
        try {
            classDate = loadClassDate(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (classDate == null) {
            throw new ClassNotFoundException();
        } else {
            return defineClass(name,classDate,0,classDate.length);
        }
    }

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        BreakClassLoader1 classLoader1 = new BreakClassLoader1();
        classLoader1.setBasePath("D:\\lib\\");
        Class<?> clazz1 = classLoader1.loadClass("com.practice.Student");
        clazz1.newInstance();
        System.out.println(clazz1.getClassLoader());
    }
}
相关推荐
忒可君4 分钟前
C# winform 报错:类型“System.Int32”的对象无法转换为类型“System.Int16”。
java·开发语言
GuYue.bing15 分钟前
网络下载ts流媒体
开发语言·python
StringerChen22 分钟前
Qt ui提升窗口的头文件找不到
开发语言·qt
牛顿喜欢吃苹果27 分钟前
linux创建虚拟串口
python
数据小爬虫@28 分钟前
如何利用PHP爬虫获取速卖通(AliExpress)商品评论
开发语言·爬虫·php
撸码到无法自拔34 分钟前
深入理解.NET内存回收机制
jvm·.net
-Mr_X-35 分钟前
FFmpeg在python里推流被处理过的视频流
python·ffmpeg
一个不秃头的 程序员1 小时前
代码加入SFTP JAVA ---(小白篇3)
java·python·github
susu10830189111 小时前
python实现根据搜索关键词爬取某宝商品信息
爬虫·python
java1234_小锋1 小时前
MyBatis如何处理延迟加载?
java·开发语言