双亲委派模型机制

news2024/11/28 12:44:25

文章目录

  • 类加载器
  • findClass
  • loadClass
  • JDK双亲委派的破坏
    • 第一次破坏
    • 第二次破坏
  • tomcat
  • 热部署
  • JDK9最新改动

双亲委派机制是当类加载器需要加载某一个.class字节码文件时,则首先会把这个任务委托给他的上级类加载器,递归这个操作,如果上级没有加载该.class文件,自己才会去加载这个.class。主要目的是为了安全,保证一个Java类在JVM的唯一性

类加载器

在这里插入图片描述

  • Bootstrap ClassLoader(启动类加载器):该类加载器由C++实现的。负责加载Java基础类,对应加载的文件是%JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等。
  • Extension ClassLoader(标准扩展类加载器):继承URLClassLoader。对应加载的文件是%JRE_HOME/lib/ext 目录下的jar和class等。
  • App ClassLoader(系统类加载器):继承URLClassLoader。对应加载的应用程序classpath目录下的所有jar和class等。
  • CustomClassLoader(用户自定义类加载器):由Java实现。我们可以自定义类加载器,并可以加载指定路径下的class文件

类加载器的父子关系不是通过继承来实现的,比如AppClassLoader并非ExtClassLoader的子类,只是AppClassLoader的parent指向ExtClassLoader对象。
所以若自定义类加载器,不是去继承AppClassLoader,而是继承ClassLoader抽象类,再重写findClass和loadClass即可

findClass

作用是根据类的路径信息,查找类,再调用defineClass 把类字节数组生成class,如果需要自定义ClassLoader的话,必须重写该方法。不打破双亲委派机制

protected Class<?> findClass(final String name)
        throws ClassNotFoundException
    {
        final Class<?> result;
        try {
            result = AccessController.doPrivileged(
                new PrivilegedExceptionAction<Class<?>>() {
                    public Class<?> run() throws ClassNotFoundException {
                        String path = name.replace('.', '/').concat(".class");
                        Resource res = ucp.getResource(path, false);
                        if (res != null) {
                            try {
                                return defineClass(name, res);
                            } catch (IOException e) {
                                throw new ClassNotFoundException(name, e);
                            }
                        } else {
                            return null;
                        }
                    }
                }, acc);
        } catch (java.security.PrivilegedActionException pae) {
            throw (ClassNotFoundException) pae.getException();
        }
        if (result == null) {
            throw new ClassNotFoundException(name);
        }
        return result;
    }

loadClass

加载类,父类不能加载时,由当前的类加载器加载,会调用findClass方法
若要打破双亲委派机制,重写loadClass

    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
              //检查指定类是否被当前类加载器加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) { //如果没被加载过,委派给父加载器加载
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false); //委托父加载器
                    } else {
                        c = findBootstrapClassOrNull(name);  //ext类加载器加载器才会走到该分支,尝试让最顶层的BootstraptClassLoader加载
                    }
                } catch (ClassNotFoundException e) {
                    //如果父加载器无法加载,会抛出 ClassNotFoundException
                  
                }

                if (c == null) {
                    // 父类不能加载,由当前的类加载器加载
                    long t1 = System.nanoTime();
                    c = findClass(name);   //需要自己加载类时,调用findClass

                    // 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;
        }
    }


JDK双亲委派的破坏

第一次破坏

在 jdk 1.2 之前,那时候还没有双亲委派模型,不过已经有了 ClassLoader 这个抽象类,所以已经有人继承这个抽象类,重写 loadClass 方法来实现用户自定义类加载器。

而在 1.2 的时候要引入双亲委派模型,为了向前兼容, loadClass 这个方法还得保留着使之得以重写,新搞了个 findClass 方法让用户去重写,并呼吁大家不要重写 loadClass 只要重写 findClass。

这就是第一次对双亲委派模型的破坏,因为双亲委派的逻辑在 loadClass 上,但是又允许重写 loadClass,重写了之后就可以破坏委派逻辑了

第二次破坏

第二次破坏指的是 JNDI、JDBC 之类的情况。

首先得知道什么是 SPI(Service Provider Interface),它是面向拓展的,也就是说我定义了个规矩,就是 SPI ,具体如何实现由扩展者实现。

像我们比较熟的 JDBC 就是如此。

MySQL 有 MySQL 的 JDBC 实现,Oracle 有 Oracle 的 JDBC 实现,我 Java 不管你内部如何实现的,反正你们这些数据库厂商都得统一按我这个来,这样我们 Java 开发者才能容易的调用数据库操作,所以在 Java 核心包里面定义了这个 SPI。

而核心包里面的类都是由启动类加载器去加载的,但它的手只能摸到\lib或Xbootclasspath指定的路径中,其他的它鞭长莫及。

而 JDBC 的实现类在我们用户定义的 classpath 中,只能由应用类加载器去加载,所以启动类加载器只能委托子类来加载数据库厂商们提供的具体实现,这就违反了自下而上的委托机制。

具体解决办法是搞了个线程上下文类加载器,通过setContextClassLoader()默认情况就是应用程序类加载器,然后利用Thread.current.currentThread().getContextClassLoader()获得类加载器来加载。

这就是第二次破坏双亲委派模型

tomcat

打破双亲委派

热部署

为了满足热部署的需求,进行不停机更新。

OSGI (开放服务网关协议,Open Service Gateway Initiative)技术是Java动态化模块化系统的一系列规范。

OSGI 就是利用自定义的类加载器机制来完成模块化热部署,而它实现的类加载机制就没有完全遵循自下而上的委托,有很多平级之间的类加载器查找。

JDK9最新改动

在这里插入图片描述

JDK 9 为了模块化的支持,对双亲委派模式做了一些改动:

  • 扩展类加载器被平台类加载器(Platform ClassLoader)取代。

JDK 9 时基于模块化进行构建(原来的 rt.jar 和 tools.jar 被拆分成数十个 JMOD 文件), 其中的 Java
类库就已天然地满足了可扩展的需求,那自然无须再保留 <JAVA_HOME>\lib\ext 目录,此前使用这个目录或者 java.ext.dirs 系统变量来扩展 JDK 功能的机制已经没有继续存在的价值了。

  • 平台类加载器和应用程序类加载器都不再继承自 java.net.URLClassLoader。

现在启动类加载器、平台类加载器、应用程序类加载器全都继承于 jdk.internal.loader.BuiltinClassLoader。

如果有程序直接依赖了这种继承关系,或者依赖了 URLClassLoader 类的特定方法,那代码很可能会在 JDK 9 及更高版本的 JDK 中崩溃。

  • 启动类加载器现在是在 Java 虚拟机内部和 Java 类库共同协作实现的类加载器(以前是 C++实现)。

为了与之前的代码保持兼容,所有在获取启动类加载器的场景(譬如 Object.class.getClassLoader)中仍然会返回 null来代替,而不会得到 BootClassLoader 的实例。

  • 类加载的委派关系也发生了变动。
    当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载。

在 Java 模块化系统明确规定了三个类加载器负责各自加载的模块:

  • 启动类加载器负责加载的模块
java.base                        java.security.sasl
java.datatransfer                java.xml
java.desktop                     jdk.httpserver
java.instrument                  jdk.internal.vm.ci
java.logging                     jdk.management
java.management                  jdk.management.agent
java.management.rmi              jdk.naming.rmi
java.naming                      jdk.net
java.prefs                       jdk.sctp
java.rmi                         jdk.unsupported

  • 平台类加载器负责加载的模块
java.activation*                jdk.accessibility
java.compiler*                  jdk.charsets
java.corba*                     jdk.crypto.cryptoki
java.scripting                  jdk.crypto.ec
java.se                         jdk.dynalink
java.se.ee                      jdk.incubator.httpclient
java.security.jgss              jdk.internal.vm.compiler*
java.smartcardio                jdk.jsobject
java.sql                        jdk.localedata
java.sql.rowset                 jdk.naming.dns
java.transaction*               jdk.scripting.nashorn
java.xml.bind*                  jdk.security.auth
java.xml.crypto                 jdk.security.jgss
java.xml.ws*                    jdk.xml.dom
java.xml.ws.annotation*         jdk.zipfs

  • 应用程序类加载器负责加载的模块
jdk.aot                         jdk.jdeps
jdk.attach                      jdk.jdi
jdk.compiler                    jdk.jdwp.agent
jdk.editpad                     jdk.jlink
jdk.hotspot.agent               jdk.jshell
jdk.internal.ed                 jdk.jstatd
jdk.internal.jvmstat            jdk.pack
jdk.internal.le                 jdk.policytool
jdk.internal.opt                jdk.rmic
jdk.jartool                     jdk.scripting.nashorn.shell
jdk.javadoc                     jdk.xml.bind*
jdk.jcmd                        jdk.xml.ws*
jdk.jconsole

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卷积神经网络<二>keras实现多分支输入VGG

VGG的模型图 VGG使用Keras实现 这里的代码借鉴了VGG实现Keras&#xff0c;但是这段代码不支持多通道&#xff0c;并且vgg函数的扩展性不好。下面修改一下&#xff0c;方便进行多分支图片输入的建立&#xff0c;以及更见方便的调参。 # from keras.models import from keras.l…

MyBatis介绍

MyBatis介绍 MyBatis 是一款优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 Java 的 POJOs(Plain Ordi…

PMP考试自学可以吗?(含PMP备考资料)

当然是可以的&#xff0c;只要解决了“报考的35学时”这个问题&#xff0c;就只剩怎么备考的问题了。 在一般情况下&#xff0c;建议备考一到三个月&#xff0c;别给自己太长或太短的备考时间&#xff0c;前者坚持不下来&#xff0c;后者备考时间太少&#xff0c;来不及备考充…

戴尔大步进军经典量子计算混合模型

​ &#xff08;图片来源&#xff1a;网络&#xff09; 戴尔正将量子计算机融入传统IT的基础架构中&#xff0c;并向新型加速计算机开放了数据中心。这家服务器制造商为传统服务器基础设施创建了一个蓝图&#xff0c;以满足量子系统的独特需求&#xff0c;量子系统速度要比经典…

基于物联网的汽车爆胎预警系统

本设计是基于物联网的汽车爆胎预警系统的设计与实现设计&#xff0c;主要实现以下功能&#xff1a; 1&#xff0c;主机用LCD1602显示温度、气压和距离&#xff1b; 2&#xff0c;主从机间通过ZigBee进行数据的传输&#xff1b; 3&#xff0c;从机检测轮胎气压&#xff0c;温度…

zbxtable

ubuntu install zbxtable 1.新建zbxtable文件夹&#xff0c;将三件套下载到本地存放 mkdir ~/zbxtable ZbxTable: https://dl.cactifans.com/zbxtable/zbxtable-2.1.0.tar.gz ZbxTable-Web: https://dl.cactifans.com/zbxtable/web.tar.gz MS-Agent: https://dl.cactifans.co…

MybatisMybatisPlusSpringboot之最全入门学习教程笔记

1 Mybatis概述 1.1 Mybatis概念 MyBatis 是一款优秀的持久层框架&#xff0c;用于简化 JDBC 开发, &#xff08;1&#xff09;持久层&#xff1a;负责将数据到保存到数据库的那一层代码。Mybatis就是对jdbc代码进行了封装。 JavaEE三层架构&#xff1a;表现层、业务层、持久层…

ftp协议主动模式与被动模式

FTP主动模式与被动模式 主动模式&#xff1a;客户端给服务端的21控制端口发命令说&#xff0c;我要下载什么什么&#xff0c;并且还会说我已经打开了自己的某个端口&#xff0c;你就从这里把东西给我吧&#xff0c;服务器知道后就会连接客户端已打开的那个数据端口把东西传给客…

SpringBoot配置https

1.Https配置 由于HTTPS具有良好的安全性&#xff0c;在开发中得到了越来越广泛的应用&#xff0c;像微信公众号、小程序等的开发都要使用HTTPS来完成。对于个人开发者而言&#xff0c;一个HTTPS 证书的价格还是有点贵&#xff0c;但是呢&#xff0c;国内的一些云服务器厂商提供…

android studio 项目生成apk的几个问题(备忘)

终于自己做的一个小东西要做完了&#xff0c;最后一步是生成apk&#xff0c;这之前遇到几个问题备忘一下。 1、安装完成后有两个图标&#xff0c;分别是两个activity&#xff0c;卸载一个&#xff0c;另一个也没了。 原因&#xff1a;我原来做一时候没有欢迎界面&#xff0c;…

总结数据结构常用树

树&#xff1a;只有一个根节点&#xff0c;有孩子结点&#xff0c;父节点 二叉树&#xff1a;每个节点最多有两个孩子结点。 二分搜索树&#xff1a;也叫二叉排序树&#xff0c;首先它是一颗二叉树&#xff0c;且左右孩子都存在时&#xff0c;左孩子都小于当前节点值&#xf…

计算机数制(进制转换,原码,反码,补码,真值)

目录 区分进制 带小数点的进制转化 进制转换练习 符号数的表示方法 区分&#xff1a; 考点&#xff1a;给你原码转换补码&#xff0c;补码最负的数的表示&#xff0c;0的表示 原码&#xff0c;反码&#xff0c;补码练习 区分进制 注意微机原理这门课用的是后缀的方式&#xff0…

小学生python游戏编程arcade----碰撞精灵消失问题

小学生python游戏编程arcade----碰撞精灵消失问题前言碰撞精灵消失问题1、多余的精灵不能及时消失1.1 问题1.2 失败代码1.3 记录备忘1.4 代码实现2、放置位置2.1 代码放在ondraw中可以2.2 在update中也可以2.3 碰撞中3、玩家子弹击中敌坦克后的爆炸效果3.1 爆炸类3.2 爆炸列表准…

2022年铁路行业研究报告

第一章 行业概况 铁路运输是主要的陆上交通运输方式之一&#xff0c;铁路是指在综合交通运输体系中&#xff0c;用于运行火车等交通工具行驶的轨道线路。铁路运输是主要的陆上交通运输方式之一&#xff0c;是通过机车牵引车辆组成列车在铁轨上运送客或货的一种运输方式。相比其…

AVL双旋转思路分析与图解

AVL树双旋转思路分析与图解 首先我们要知道什么情况之下我们是要进行双旋转? 当最小不平衡子树为LR型或者RL型的时候, 那么什么时候最小不平衡子树是RL型或者什么时候又是LR型的? 下面我们就先给出LR型, RL型, LL型, RR型最小不平衡子树的概念: LR型最小不平衡子树: 首先拿…

Linux 动静态库

目录 静态库和动态库 gcc规则使用动静态库的规则&#xff1a; 制作静态库 使用静态库 方法1. 方法2. 制作动态库 使用动态库 方法1&#xff1a; 方法2&#xff1a; 方法3&#xff1a; 方法4&#xff1a; 进程&#xff0c;静态库&#xff0c;动态库 静态库和动态库 …

传统瀑布模型和实际瀑布模型

传统瀑布模型&#xff1a; 瀑布模型是所有模型的基础框架 特点&#xff1a; 线性的开发流程&#xff0c;不能够应对需求的变化。 必须等前一阶段的工作完成后&#xff0c;才能开始后一阶段的工作 前一阶段的输出文档就是后一阶段的输入文档&#xff0c;因此只有前一阶段的输…

Map及其实现类、锁

HashMap、HashTable、ConcurrentHashMap 区别 一.HashMap和HashTable的区别 1、两者父类不同 HashMap是继承自AbstractMap类&#xff0c;而Hashtable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable&#xff08;可复制&#xff09;、Serializable&#xff0…

朱松纯教授场景理解相关文章简介

朱松纯教授场景理解相关文章简介 Holistic 3D Scene Parsing and Reconstruction from a Single RGB Image 基于单张图像的整体场景解译与重建 我们提出了一个计算框架来联合解译单帧RGB图像&#xff0c;通过使用一系列的随机语法模型生成的CAD模型构成整体的3D结构。具体地说…

智慧农业SaaS系统

真正的大师,永远都怀着一颗学徒的心&#xff01; 一、项目简介 智慧农业SaaS系统 二、实现功能 监控管理&#xff1a;支持海康摄像头监控。 用户管理&#xff1a;支持用户是系统操作者&#xff0c;该功能主要完成系统用户配置。 岗位管理&#xff1a;支持配置系统用户所属担…