文章目录

  • 双亲委派机制概述
  • 双亲委派机制原理
  • 双亲委派机制的优势
  • 沙箱安全机制
  • 破坏双亲委派机制

双亲委派机制概述

  • Java虚拟机对class文件采用按需加载的方式,也就是说当需要使用该类时,才会将它的class文件加载到内存生成class对象。而且加载某个类的文件是,采用的是双亲委派机制,即把请求交由父类处理,它是一种任务委派模式。
  • 先看下面的一个例子
    新建一个 java.lang 包,在下面自定义一个String类 ,如图

    然后在Test中创建String类
public class Test {public static void main(String[] args) throws ClassNotFoundException {String string = new String();java.lang.String s2 = new java.lang.String();System.out.println("hello");}
}

如果创建的对象是我们自定义的类则会输出静态代码块中的 ““我是自定义 String …””,否则不会。
这里结果指定是不会打印的,这就是双亲委派机制的作用。

双亲委派机制原理

  • 如果一个类加载器接收到了类加载请求,它并不会自己先去加载,而是把这个类加载委托给父类加载器去执行。
  • 如果父类加载器还存在父加载器,则进一步向上委托,依次递归,请求将最终达到顶层的启动类加载器。
  • 如果父类可以完成类加载任务,就成功返回,若父类无法完成类加载任务,子加载器才会尝试去加载,这就是双亲委派模式。
  • 如果将上面的代码 main方法放在自定义的 String 类中
public class String {static {System.out.println("我是自定义 String ...");}public static void main(String[] args) {System.out.println("main....");}
}

执行的时候报错如下:


意思就是加载的 java.lang.String 类中没有 main方法,也证明了之前的结论。

双亲委派机制的优势

  • 避免类重复加载
  • 保护程序安全,避免核心API被随意篡改。(如上面的自定义 java.lang.String 类)也包括阻止我们使用和核心api相同的包名来自定义类。

如下图

报错如下:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.langat java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)at java.lang.ClassLoader.defineClass(ClassLoader.java:761)at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)at java.net.URLClassLoader.access$100(URLClassLoader.java:73)at java.net.URLClassLoader$1.run(URLClassLoader.java:368)at java.net.URLClassLoader$1.run(URLClassLoader.java:362)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:361)at java.lang.ClassLoader.loadClass(ClassLoader.java:424)at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)at Test.main(Test.java:5)

沙箱安全机制

  • 自定义String类,但是在加载自定义String类时会率先使用引导类加载器加载,而引导类加载器在加载过程中会优先加载jdk自带的文件,上面例子报错信息说没有 main 方法,就是因为加载的是 jdk的 java.lang包下的String类。这样可以保证java源码的保护,这就是沙箱安全机制。

破坏双亲委派机制

  • 双亲委派机制模型并不是一个具有强制性约束的模型,而是 Java 设计者推荐给开发者们的类加载实现方式。在 Java 的世界中,大部分类加载都遵循了这个模型,但也有例外的情况。直到Java模块化出现,双亲委派机制已经有三次较大规模“被破坏”的情况。
  • 双亲委派模型第一次被破坏:

双亲委派模型第一次被破坏发生在双亲委派模型出现之前,即jdk1.2 之前。由于双亲委派模型在jdk1.2以后才被引入,但是类加载的概念和抽象类 ClassLoader 已经存在,面对已经存在的用户自定义类加载器代码,Java设计者们引入双亲委派模型不得不作出一些妥协,为了兼容这些已有代码,无法再以技术手段避免 loadClass() 被自类覆盖的可能,只能在 jdk1.2以后的java.lang.ClassLoader 中添加一个新的 protected 方法 findClass() ,并引导用户编写的类加载器逻辑尽可能去重写这个方法,而不是在 loadClass() 中编写代码。loadClass() 方法中,双亲委派的具体逻辑就写在这里面,按照loadClass的逻辑,如果父类加载失败,会自动调用自己的 findClass() 方法来完成加载。这样既不影响用户按照自己的意愿去加载类,也不会破坏双亲委派规则。

  • 双亲委派模型第二次破坏

双亲委派模型的第二次破坏是由这个模型自身的缺陷导致的,双亲委派机制很好的解决了各个类加载器协作时基础类型一致的问题(越基础的类由越上层的类加载器加载),基础类型之所以被称为基础,是因为它们总是作为用户代码继承、调用的API存在,但是程序设计往往没有完美的存在,如果有基础类型需要调用用户的代码,那该怎么办呢?
一个典型的例子就是JNDI服务,JNDI现在已经是Java的标准服务,它的代码由启动类加载器完成,肯定属于Java中很基础的类型了。但JNDI存在的目的是对资源进行查找和集中管理,它需要调用由其他厂商实现并部署的应用程序的 ClassPath 下的JNDI服务提供者接口的代码,启动类加载器是绝对不会认识这些类的,那该怎么办呢?

为了解决这个困境,Java设计团队引入了不太优雅的设计:线程上下文加载器。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程时还未设置,它将会从父类中继承一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。

有了线程上下文类加载器,程序就可以做一些“舞弊”的事情了。JNDI服务使用这个线程上下文类加载器去加载所需的SPI服务代码,这是一种父类加载器去请求子类加载器完成类加载的行为,这种行为实际上是打通了双亲委派模型的层次结构来逆向使用类加载器,已经违背了双亲委派模型的一般性原则。不过当SPI的服务提供者多于一个的时候,代码就只能根据具体提供者的类型来硬编码来判断,为了消除这种及其不优雅的实现方式,在JDK6时,如果不是提供了java.util.ServiceLoader,以META-INF/Services中的配置信息,辅以责任链模式,才算是给SPI的加载提供了一种相对合理的解决方案。

  • 双亲委派模型的第三次破坏

双亲委派模型的第三次破坏时用户追求程序动态性而导致的(如:代码热替换,模块热部署,等),就是希望Java程序能像我们电脑外设那样,接上鼠标键盘,不用重启电脑就可以使用。

OSGI 实现模块化部署的关键是它自定义的类加载机制的实现,每一个应用程序模块都有自己的一个类加载器,当需要更换一个Bundle时,就把Bundle连同类加载器一起换掉以实现代码的热替换。在OSGI环境下,类加载器不在是双亲委派模型推荐的树状模型,而是进一步发展为更复杂的网状结构,当收到类加载请求时,OSGI将按照以下顺序进行类搜索:

  • 将以Java开头的类,委托给父类加载器
  • 否则,将委派列表名单内的类,委派给父类加载器加载
  • 否则,将Import列表中的类,委派给Export这个类的Bundle的类加载器加载。
  • 否则,查找当前Bundle的ClassPath,使用自己的类加载器加载。
  • 否则,查找类是否在自己的Fragment Bundle中,如果在则委派给 Fragment bundle的类加载器加载。
  • 否则,查找Dynamic Import 列表的Bundle,委派给对应Bundle的类加载器加载。
  • 否则,类查找失败。

上面查找顺序中,只有前两条符合按照双亲委派模型原则,其余查找类都是在平级的类加载器中进行的。

  • 双亲委派模型的破坏并不一定都是贬义的,只要有明确的目的和充分的理由,突破原有规则无疑也是一种创新。

Java虚拟机-双亲委派机制相关推荐

  1. Java虚拟机 - 双亲委派机制

    文章目录 一.原理 二.作用 三.沙箱安全机制 四.补充内容 Java虚拟机对class文件采用的是 按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象.而且 ...

  2. 关于Java类加载双亲委派机制的思考(附面试题)

    转载自 关于Java类加载双亲委派机制的思考(附面试题) 预定义类加载器和双亲委派机制 JVM预定义的三种类型类加载器: 启动(Bootstrap)类加载器:是用本地代码实现的类装入器,它负责将 &l ...

  3. Java的双亲委派机制

    Java的双亲委派机制是java中类加载过程采用的机制,所以首先要理解java的类加载过程. 类加载过程:程序经过javac.exe命令以后,会生成一个或多个class字节码文件,接着使用java.e ...

  4. java类加载机制为什么双亲委派_[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的...

    Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的不过源码其实比较简单,接下来简单介绍一下我们先从启动类说起有一个Launcher类 ...

  5. Java打破双亲委派机制

    1.自定义加载器 沿用双亲委派机制自定义类加载器很简单,只需继承ClassLoader类并重写findClass方法即可. ①先定义一个待加载的类Test,它很简单,只是在构建函数中输出由哪个类加载器 ...

  6. 「 JVM基础 」Java双亲委派机制

    Java的双亲委派机制 参考&鸣谢 Dream_ling. weixin_39610188. JVM底层原理解析 文章目录 Java的双亲委派机制 一.介绍 二.什么是双亲委派机制 三.双亲委 ...

  7. Java双亲委派机制在Android的应用

    Java的双亲委派机制 三层类加载器 1.启动类加载器(Bootstrap Class Loader) 这个类加载器负责加载存放在<JAVA_HOME>\lib目录,或者被-Xbootcl ...

  8. JAVA 双亲委派机制

    最近突然看到了关于Java的双亲委派机制,作为一个搞Java的程序猿还是应该知道是怎么回事. 我用一个程序来简单说明是怎么回事吧 package java.util;/*** 本类中的main方法不会 ...

  9. java虚拟机中的双亲委派机制

    文章目录 双亲委派机制 工作原理 工作场景 调用过程 三种加载器调用范围 String类加载过程 StringTest类加载过程 双亲委派机制优点 双亲委派机制 Java虚拟机对class文件采用的是 ...

最新文章

  1. 软件自动测试框架,软件自动化测试框架的研究和实现
  2. php div图片局部刷新,前端jquery 后端 thinkphp 实现局部刷新
  3. UseControls ————用户自定义控件的textbox的传值问题
  4. 通过从全局和类内部重载operator new /delete来获取内存管理权
  5. 安装gem_Python安装第三方库及常见问题处理方法汇总
  6. Android逆向笔记-某水果大作战内购破解思路
  7. 将叶节点连接成一个链表☆
  8. 分布式红锁的加锁失败的设计原理
  9. UTF-8的CSV文件中文乱码问题解决办法
  10. SCCM2007系列教程之十操作系统部署(三)
  11. jQuery焦点图插件
  12. zk和redis分布式锁比较
  13. java import list_Java中的List集合
  14. 如何查看mysql的sql语句索引_mysql 查看sql语句索引情况 详解explain
  15. Resource Hacker-资源替换工具
  16. blender中常用快捷键的总结
  17. Mac电脑没声音了怎么办?苹果电脑没声音的解决方法
  18. 字符串模式匹配——BF算法
  19. Ubuntu 15.04 搜狗输入法 无法切换到英文输入
  20. 全国青少年信息学奥林匹克竞赛到底是什么?

热门文章

  1. [原创] PS美女转手绘效果
  2. 我的Citavi初体验,比mendeley更好使的软件
  3. 学习笔记:EXCEL外卖商家营业数据周报制作
  4. 小米5预装android版本,小米 Mi5(小米5 安卓8.0)获取Root权限服务含精简系统方案...
  5. redis 命令之获取缓存过期时间
  6. 一招教你轻松看懂波特图
  7. Matlab标准化(单位化)一个向量
  8. 美和易思云南农职项目“升格”开门红!
  9. 如何申请成为中国支付清算协会会员
  10. 【模电】电场、磁场、电磁场的屏蔽原理