双亲委派

来源:互联网 发布:双十一抢单源码 编辑:程序博客网 时间:2024/04/30 18:07

1.Java加载器组织结构简单说明

每一个类加载器都有一个父加载器,这种父加载器不是通过继承来实现,即:
(类的加载可参见:Java类的加载)

Class MyClassLoader extends ClassLoader{}//这种只是声明定义自己的加载器,而不是ClassLoader是其父加载器,事实上ClassLoader是抽象类

它事实上是通过组合关系来实现的:

//ClassLoader源码:private final ClassLoader parent;

除了启动类加载器,所有的类加载器都有父加载器。
图示:
这里写图片描述

(1).BootStrap ClassLoader:启动类加载器,负责加载存放在%JAVA_HOME%\lib目录中的,或者通被-Xbootclasspath参数所指定的路径中的,并且被java虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库,即使放在指定路径中也不会被加载)类库到虚拟机的内存中,启动类加载器无法被java程序直接引用。
(2).Extension ClassLoader:扩展类加载器,由sun.misc.LauncherExtClassLoader(3).ApplicationClassLoadersun.misc.LauncherAppClassLoader实现,负责加载用户类路径classpath上所指定的类库,是类加载器ClassLoader中的getSystemClassLoader()方法的返回值,开发者可以直接使用应用程序类加载器,如果程序中没有自定义过类加载器,该加载器就是程序中默认的类加载器。

注:在Java中,任意一个类都需要由加载它的类加载器和这个类本身一同确定其在java虚拟机中的唯一性,即比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提之下才有意义,否则,即使这两个类来源于同一个Class类文件,只要加载它的类加载器不相同,那么这两个类必定不相等(这里的相等包括代表类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法和instanceof关键字的结果)。

2.所谓双亲委派

双亲委派的工作过程:一个类加载器每次加载类的时候,它不会自己试图加载,而是委托给其父类加载器加载,因为每一个非启动类加载器都有父类加载器,所以递归的,最终这个类都会由启动类加载器首先试图加载,如果加载不成功,则由这条加载器链的下一个加载器试图加载,以此类推,直到加载成功或到最后加载失败。
实现:

//这个方法是可以重写的,但不推荐,重写会破坏双亲委派模型,推荐重写findClass方法protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {            /**             * 最先,会查找该类是否已经被加载过             * 这里的查找是native方法实现,其实现逻辑是同一个全名称类+同             * 一个加载器方为同一个类,方为该类已加载             */            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异常由最末加载器抛出                }                if (c == null) {                    //父加载器无法加载,则由自己试图加载                    long t1 = System.nanoTime();                    c = findClass(name);                    // 记录加载信息                    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类随着它的加载器一起具备了一种带有优先级的层次关系.

例如类java.lang.Object,它存放在rt.jart之中.无论哪一个类加载器都要加载这个类.最终都是双亲委派模型最顶端的Bootstrap类加载器去加载.因此Object类在程序的各种类加载器环境中都是同一个类.相反.如果没有使用双亲委派模型.由各个类加载器自行去加载的话.如果用户编写了一个称为“java.lang.Object”的类.并存放在程序的ClassPath中.那系统中将会出现多个不同的Object类.java类型体系中最基础的行为也就无法保证.应用程序也将会一片混乱.

注:双亲委派模型是Java设计者推荐给开发者的类加载器的实现方式,并不是强制规定的。大多数的类加载器都遵循这个模型,但是JDK中也有较大规模破坏双亲模型的情况,例如线程上下文类加载器(Thread Context ClassLoader)的出现,具体分析可以参见周志明著《深入理解Java虚拟机》。

0 0