Java双亲委派

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.Launcher ExtClassLoader(3).ApplicationClassLoadersun.misc.Launcher E x t C l a s s L o a d e r 实 现 , 负 责 加 载 ( 3 ) . A p p l i c a t i o n C l a s s L o a d e r : 应 用 程 序 类 加 载 器 , 由 s u n . m i s c . L a u n c h e r AppClassLoader实现,负责加载用户类路径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虚拟机》。

### Java双亲委派机制原理 Java 中的双亲委派机制是一种类加载器的工作模型,其主要目的是为了确保类的唯一性和安全性。在这种机制下,当某个类加载器收到类加载请求时,它不会立即尝试自己去加载这个类,而是先把这个请求委派给父类加载器处理,只有当父类加载器无法完成加载任务时,才会由当前类加载器自行加载[^1]。 #### 双亲委派机制的核心流程 双亲委派机制的具体执行过程如下: - 当一个类加载器接收到类加载请求时,会优先将此请求交给它的父类加载器来处理。 - 如果父类加载器能够成功加载,则返回所加载的类;如果父类加载器无法加载(即在其命名空间中未找到此类),则子类加载器再尝试自己加载该类[^2]。 这种设计的好处在于可以避免重复加载同一个类的情况发生,并且保证了基础库的安全性——因为核心类总是由启动类加载器负责加载,从而防止恶意代码替换标准库中的关键组件。 #### 自定义类加载器与打破双亲委派机制 尽管双亲委派机制非常有效,但在某些特殊场景下可能需要绕过这一规则。例如,在实现热部署或者插件化架构时,就需要使用自定义类加载器并重新定义加载逻辑。要打破默认的双亲委派行为,可以通过继承 `java.lang.ClassLoader` 并覆盖其中的方法来达成目标: ```java public class CustomClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] b = loadClassData(name); return defineClass(name, b, 0, b.length); // 定义新的类对象 } private byte[] loadClassData(String className){ // 实现具体的字节码读取逻辑... return new byte[0]; } } ``` 上述代码展示了如何创建一个简单的自定义类加载器并通过覆写 `findClass()` 方法来自行控制类的查找方式[^4]。 ### 总结 综上所述,双亲委派机制是 Java 类加载体系的重要组成部分之一,对于维护 JVM 的稳定运行起到了不可替代的作用。然而,在面对特定需求时也可以灵活调整甚至完全规避这套机制以满足实际开发中的多样化要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值