双亲委派 深藏阁楼爱情的钟 2021-09-24 03:28 383阅读 0赞 # 为什么需要双亲委派呢 ? # **首先:对于任意一个类,都需要由加载它的类加载器和这个类本身来一同确立其在Java虚拟机中的唯一性。我们知道,判断一个类是否相同,通常用equals()方法,isInstance()方法和isAssignableFrom()方法。来判断,对于同一个类,如果没有采用相同的类加载器来加载,在调用的时候,会产生意想不到的结果。因为如果不是同一个类加载器加载,即使是相同的class文件,也会出现判断不想同的情况,从而引发一些意想不到的情况,为了保证相同的class文件,在使用的时候是相同的对象,jvm设计的时候,采用了双亲委派的方式来加载类。** ## 双亲委派原则 ## **双亲委派**:如果一个类加载器收到了加载某个类的请求,则该类加载器并不会去加载该类,而是把这个请求委派给父类加载器,每一个层次的类加载器都是如此,因此所有的类加载请求最终都会传送到顶端的启动类加载器;只有当父类加载器在其搜索范围内无法找到所需的类,并将该结果反馈给子类加载器,子类加载器会尝试去自己加载。 他的工作流程是: 当一个类加载器收到类加载任务,会先交给其父类加载器去完成,因此最终加载任务都会传递到顶层的启动类加载器,只有当父类加载器无法完成加载任务时,才会尝试执行加载任务。这个理解起来就简单了,比如说,另外一个人给小费,自己不会先去直接拿来塞自己钱包,我们先把钱给领导,领导再给领导,一直到公司老板,老板不想要了,再一级一级往下分。老板要是要这个钱,下面的领导和自己就一分钱没有了。(例子不好,理解就好) 采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object对象。双亲委派原则归纳一下就是: 1、可以避免重复加载,父类已经加载了,子类就不需要再次加载 2、更加安全,很好的解决了各个类加载器的基础类的统一问题,如果不使用该种方式,那么用户可以随意定义类加载器来加载核心api,会带来相关隐患。 ## JVM提供了三种系统加载器: ## 1、启动类加载器(Bootstrap ClassLoader):C++实现,在java里无法获取,负责加载<JAVA\_HOME>/lib下的类。 2、扩展类加载器(Extension ClassLoader): Java实现,可以在java里获取,负责加载<JAVA\_HOME>/lib/ext下的类。 3、系统类加载器/应用程序类加载器(Application ClassLoader):是与我们接触对多的类加载器,我们写的代码默认就是由它来加载,ClassLoader.getSystemClassLoader返回的就是它。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjI5NTQz_size_16_color_FFFFFF_t_70] ## 双亲委派的实现 ## 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); // 前面提到,bootstrap classloader的类加载器为null,通过find方法来获得 } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } if (c == null) { // 如果还是没有获得该类,调用findClass找到类 long t1 = System.nanoTime(); c = findClass(name); // jvm统计 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } // 连接类 if (resolve) { resolveClass(c); } return c; } } ## 为什么要破坏双亲委派?(JDBC为例) ## 在连接mysql数据库时,需要使用 `Class.forName("com.mysql.jdbc.Driver");`来加载mysql的驱动。好了,问题来了,Class.forName()加载用的是调用者的Classloader,这个调用者DriverManager是在rt.jar中的,ClassLoader是启动类加载器,而com.mysql.jdbc.Driver肯定不在<JAVA\_HOME>/lib下,所以肯定是无法加载mysql中的这个类的。这就是双亲委派模型的局限性了,父级加载器无法加载子级类加载器路径中的类。 那么,这个问题如何解决呢?按照目前情况来分析,这个mysql的drvier只有应用类加载器能加载,那么我们只要在启动类加载器中有方法获取应用程序类加载器,然后通过它去加载就可以了。这就是所谓的**线程上下文加载器**。线程上下文类加载器可以通过Thread.setContextClassLoaser()方法设置,如果不特殊设置会从父类继承,一般默认使用的是应用程序类加载器很明显,线程上下文类加载器让父级类加载器能通过调用子级类加载器来加载类,这打破了双亲委派模型的原则 # 总结 # **这个时候我们再看下整个mysql的驱动加载过程:** 第一,获取线程上下文类加载器,从而也就获得了应用程序类加载器(也可能是自定义的类加载器) 第二,从META-INF/services/java.sql.Driver文件中获取具体的实现类名“com.mysql.jdbc.Driver” 第三,通过线程上下文类加载器去加载这个Driver类,从而避开了双亲委派模型的弊端 很明显,mysql驱动采用的这种spi服务确确实实是破坏了双亲委派模型的,毕竟做到了父级类加载器加载了子级路径中的类。 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjI5NTQz_size_16_color_FFFFFF_t_70]: /images/20210923/e35f46a209404500a29e3ca02df93463.png
相关 双亲委派机制 JVM提供了三种类加载器,分别为启动类加载器(Bootstrap Classloader)、扩展类加载器(Extention Classloader)和应用程序类加载器(App 末蓝、/ 2022年11月15日 03:56/ 0 赞/ 227 阅读
相关 双亲委派机制 > 双亲委派机制 > JVM类加载器是有亲子层级结构的,如下图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shado 清疚/ 2022年09月08日 06:19/ 0 赞/ 187 阅读
相关 Java双亲委派 1.Java加载器组织结构简单说明 每一个类加载器都有一个父加载器,这种父加载器不是通过继承来实现,即: (类的加载可参见:[Java类的加载][Java]) 港控/mmm°/ 2022年06月17日 00:55/ 0 赞/ 150 阅读
相关 双亲委派机制 ![这里写图片描述][70] 上图中展示的类加载器之间的这种层次关系,称为类加载器的双亲委派模型。双亲委派模型除了顶层的启动类加载器之外,其余的类加载器都应当有自己的父类加 水深无声/ 2022年05月16日 02:53/ 0 赞/ 266 阅读
相关 双亲委派模型 双亲委派模型 类与类加载器 双亲委派模型 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到 野性酷女/ 2022年03月10日 14:28/ 0 赞/ 246 阅读
相关 双亲委派 父类加载器和子类加载器不一定是继承关系; 除了BootstrapLoader,每个类加载器都有一个父类加载器 类加载器之间的父子关系何时建立?在自定义加载器的构造方法编 痛定思痛。/ 2021年12月19日 03:41/ 0 赞/ 257 阅读
相关 双亲委派模型 双亲委派模型 双亲委派模型简介 双亲委派模型实现源码分析 双亲委派模型的好处 双亲委派模型简介 每一个类都有一个对应它的类加载器。系统中的类加载 不念不忘少年蓝@/ 2021年11月10日 14:28/ 0 赞/ 610 阅读
相关 双亲委派模型 双亲委派模型(Since JDK.2): ![这里写图片描述][70] 从虚拟机的角度来看,类加载器主要分为启动类加载器(Bootstrap Classloader)和 £神魔★判官ぃ/ 2021年09月26日 14:36/ 0 赞/ 579 阅读
相关 双亲委派模型 围绕这四个问题去回答一下: 1. 什么是双亲委派模型 2. 为什么会有双亲委派模型 3. 可以打破双亲委派模型? 4. 为什么要打破双亲委派模型? 一、 ╰+攻爆jí腚メ/ 2021年09月25日 11:08/ 0 赞/ 354 阅读
相关 双亲委派 为什么需要双亲委派呢 ? 首先:对于任意一个类,都需要由加载它的类加载器和这个类本身来一同确立其在Java虚拟机中的唯一性。我们知道,判断一个类是否相同,通常用equal 深藏阁楼爱情的钟/ 2021年09月24日 03:28/ 0 赞/ 384 阅读
还没有评论,来说两句吧...