通俗易懂的双亲委托

双亲委托模型

一、什么是双亲委托

​ 双亲委派模型,就是如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模型

二、源码分析

Class aClass = ClassLoader.getSystemClassLoader().loadClass("MainActivity");

​ 首先,我们先看下,像上述一个类(MainActivity)是如何通过反射被加载出来的

//public abstract class ClassLoader
protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
        // First, check if the class has already been loaded
        //1.首先看该类是否应加载过,有则直接返回
        Class<?> c = findLoadedClass(name);
        if (c == null) {
        //2.没有加载过,则调用parent.loadClass方法去父类中去加载
            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
            }
			//3.当父类中不存在时,则自己通过findClass方法去加载
            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                c = findClass(name);
            }
        }
        //4.返回该对象
        return c;
}

如图中的代码,整体的逻辑为,当我们根据类名加载一个类时,

1.首先看该类是否应加载过,有则直接返回

2.没有加载过,则调用parent.loadClass方法去父类中去加载

3.当父类中不存在时,则自己通过findClass方法去加载

4.返回该对象

三、理解

​ 上述的代码,就是一个标准的双亲委托模型,就完了,就怎么多,怎么样,是不是感觉内容很少,和脑海中对他的幻想存在很多差别,现在,咱们就从上面的代码来看看这个模型的好处在哪里,优势是什么

​ 举个例子,假设一个类加载器的结构是这样的AClassLoader extends BClassLoader,BClassLoader extends ClassLoader。当AClassLoader 中有一个Test.class类,BClassLoader中也有一个Test.Class类时,我们调用AClassLoader .loadClass(“Test”);时,加载的是哪个类呢?

​ 根据上面的源码逻辑,当我们调用aClassLoader.loadClass方法时,先看该类是否加载过,在首次时没有加载过,则调用父bClassLoader的loadClass方法,b也因首次请求未加载过该类,则请求基类ClassLoader,ClassLoader中也没有,由于是根类,则通过该类的findclass方法去找,未找到,则通知bClassLoader未空的结果,b则根据空结果,去自身的findclass方法中去查找,找到了,则返回该B 中的Test.class。

四、优势

​ **1.这种层级关系可以避免重复加载:**Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。

​ **2.在安全的角度,可以在一定程度上方式源码被替换:**假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

五.自定义类加载器

​ 一个简单的自定义类加载器的方式如下

public class test extends ClassLoader{

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        //如果你想破坏双亲委托的模型,你可以重写这个方法.毕竟用户的需求是多种多样的,你开发出一个甜品店,保不齐有人非要过来买条狗。。
        return super.loadClass(name);
    }


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //如果你想保持双亲委托的模型,请重写这个方法
        return super.findClass(name);
    }
}

​ 原因则可以参照源码分析时的过程来理解(当父类中不存在时,则自己通过findClass方法去加载),并且,原生的注释也对这两个方法的用途解释的很明白了

/**
 * Loads the class with the specified <a href="#name">binary name</a>.
 * This method searches for classes in the same manner as the {@link
 * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
 * machine to resolve class references.  Invoking this method is equivalent
 * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
 * false)</tt>}.
 *
 * @param  name
 *         The <a href="#name">binary name</a> of the class
 *
 * @return  The resulting <tt>Class</tt> object
 *
 * @throws  ClassNotFoundException
 *          If the class was not found
 */
public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

 /**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param  name
     *         The <a href="#name">binary name</a> of the class
     *
     * @return  The resulting <tt>Class</tt> object
     *
     * @throws  ClassNotFoundException
     *          If the class could not be found
     *
     * @since  1.2
     */
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章