美文网首页Java 核心技术
java为什么要实现“双亲委派机制”?

java为什么要实现“双亲委派机制”?

作者: 程序员阿牛 | 来源:发表于2021-06-09 16:55 被阅读0次

答案:

1、安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改

2、避免类重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性

首先:

解释之前,我们先来看一张图

其次:

为了解答问题,这里借类加载的关键代码复习一下,请见如下代码

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();

                }

            }

            // 解析class文件,就是将符号引用替换为直接引用的过程

            if (resolve) {

                resolveClass(c);

            }

            return c;

        }

    }

首先,检查一下指定名称的类是否已经加载过,如果已经加载过了,就不需要再加载,直接 返回。

如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加 载器加载(即调用parent.loadClass(name, false);),或者是调用bootstrap类加载器来加 载。

如果父加载器及bootstrap类加载器都没有找到指定的类,那么用当前类加载器的 findClass方法来完成类加载。

为了进一步证明双亲委派的作用,我们自己写一个String类,并且包名是一致的,看会不会被加载。

package java.lang;

public final class String

        implements java.io.Serializable, Comparable<String>, CharSequence{

    @Override

    public int length() {

        return 0;

    }

    @Override

    public char charAt(int index) {

        return 0;

    }

    @Override

    public CharSequence subSequence(int start, int end) {

        return null;

    }

    @Override

    public int compareTo(String o) {

        return 0;

    }

    public static void main(String[] args) {

        System.out.println("测试类加载机制");

    }

}

执行main方法,结果出现以下报错

说明:jvm加载的并不是我们自己写的String类,而是jdk中的String类,所以这个测试证明了类加载有双亲委派机制的存在,同时证明双亲委派机制的其中一个目的就是确保Jdk的核心API的安全,不被篡改,以免造成严重的后果

有同学会说,我如果自己写一个自定义加载器,岂不是就可以打破“安全机制了”,那我们自己写一个加载器来加载我们自己写的String类吧,

自定义加载器如下:

package com.kuya123;

import java.io.FileInputStream;

import java.lang.reflect.Method;

public class CrossClassLoaderTest {

    static class CrossClassLoader extends ClassLoader {

        private String classPath;

        public CrossClassLoader(String classPath) {

            this.classPath = classPath;

        }

        private byte[] loadByte(String name) throws Exception {

            name = name.replaceAll("\\.", "/");

            FileInputStream fis = new FileInputStream(classPath + "/" + name + ".class");

            int len = fis.available();

            byte[] data = new byte[len];

            fis.read(data);

            fis.close();

            return data;

        }

        protected Class<?> findClass(String name) throws ClassNotFoundException {

            try {

                byte[] data = loadByte(name);

                return defineClass(name, data, 0, data.length);

            } catch (Exception e) {

                e.printStackTrace();

                throw new ClassNotFoundException();

            }

        }

        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) {

                    // 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.getFindClassTime().addElapsedTimeFrom(t1);

                    sun.misc.PerfCounter.getFindClasses().increment();

                }

                if (resolve) {

                    resolveClass(c);

                }

                return c;

            }

        }

    }

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

        CrossClassLoader classLoader = new CrossClassLoader("/Users/chenrui/IdeaProjects/crosstest/target/classes");

        //尝试用自己改写类加载机制去加载自己写的java.lang.String.class

        Class clazz = classLoader.loadClass("java.lang.String");

        Object obj = clazz.newInstance();

        Method method = clazz.getDeclaredMethod("print", null);

        method.invoke(obj, null);

        System.out.println(clazz.getClassLoader().getClass().getName());

    }

}

这就是java安全机制中对于恶意代码所采取的防护措施

第二点原因:

java虚拟机只会在不同的类的类名相同且加载该类的加载器均相同的情况下才会判定这是一个类。如果没有双亲委派机制,同一个类可能就会被多个类加载器加载,如此类就可能会被识别为两个不同的类,相互赋值时问题就会出现

首发自:https://www.kuya123.com/2021/06/06-20-35-26

相关文章

  • 从类加载开始的JVM学习

    目录 引言 java类加载流程 java类加载机制- 类加载原理- 双亲委派机制 Tomcat中双亲委派机制的应用...

  • 深入理解Tomcat(五)类加载机制

    前言 我们知道,Java默认的类加载机制是通过双亲委派模型来实现的。而Tomcat实现的方式又和双亲委派模型有所区...

  • 为什么使用双亲委派机制?

    为什么使用双亲委派机制? 专业名词 说双亲委派机制就不得不说类加载器。 引导类加载器:加载%JAVA_HOME%/...

  • java为什么要实现“双亲委派机制”?

    答案: 1、安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API...

  • SPI的ClassLoader问题

    问题 为什么说spi服务机制破坏了双亲委派模型? 双亲委派机制 启动类加载器(Bootstrap ClassLoa...

  • java双亲委派模型及其破坏

    这里不再介绍java的类加载机制,只谈关于双亲委派在理解上的坑。 1. 双亲委派并不是要委派给两个 而是只委派给p...

  • Tomcat类载入器

    大家都知道,Java的类加载机制是双亲委派模型,那么什么是双亲委派模型呢?我们这里简要的说一下,双亲委派模型...

  • 简单了解什么是双亲委派机制?

    什么是双亲委派机制 了解双亲委派,需要先了解下JAVA的类加载器ClassLoader,java的类加载器主要有以...

  • JVM双亲委派机制

    什么是双亲委派机制? 要想搞明白什么是双亲委派机制就要先知道三个概念 1. 什么是类的加载? 将java代码通过类...

  • Java双亲委派机制

    什么是双亲委派机制 当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个...

网友评论

    本文标题:java为什么要实现“双亲委派机制”?

    本文链接:https://www.haomeiwen.com/subject/jmieeltx.html