Java虚拟机详解(七)------双亲委派机制
2021-03-27 15:26
标签:main 二进制流 自己的 并且 自定义 字节码 详细 string类 源码 我们知道,在JDK源码中,有各种Java自带的类,比如java.lang.String,java.util.List等,那么我们自己的项目中,能够写一个命名为java.lang.String.java 等JDK源码中存在的类,并且在项目中使用吗? 1、类加载器 什么是类加载器?上篇博客我们介绍类加载过程中的第一个阶段——加载,作用是“通过一个类的全限定名来获取描述此类的二进制流”,那么这个加载过程就是由类加载器来完成的。 从Java虚拟机的角度出发,只存在两种不同的类加载器,一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用 C++ 语言实现,是虚拟机自身的一部分;另一种是所有其它的类加载器,这些类加载器都是由Java语言实现的。但是从Java开发人员的角度来看,类加载器可以细分为如下四种: ①、启动类加载器(Bootstrap ClassLoader) 负责将存放在 JDK 中的源码类大都是由启动类加载器加载,比如前面说的 java.lang.String,java.util.List等,需要注意的是,启动类 main Class 也是由启动类加载器加载。 ②、扩展类加载器(Extension ClassLoader) 这个类加载器由 sun.misc.Launcher$ExtClassLoader 实现,负责加载<JAVA_HOME>/lib/ext 目录中的,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库。 开发者可以直接使用扩展类加载器。 ③、应用程序类加载器(Application ClassLoader) 由 sun.misc.Launcher$AppClassLoader 实现。由于这个类加载器是 ClassLoader.getSystemClassLoader() 方法的返回值,所以一般也称它为系统类加载器。 它负责加载用户类路径ClassPath上所指定的类库,开发者可以直接使用这个类加载器。如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。 通常项目中自定义的类,都会放在类路径下,由应用程序类加载器加载。 ④、自定义类加载器(User ClassLoader) 这是由用户自己定义的类加载器,一般情况下我们不会自定义类加载器,但有些特殊情况,比如JDBC能够通过连接各种不同的数据库就是自定义类加载器来实现的,具体用处会在后文详细介绍。 2、双亲委派模型 回到文章开头提出的问题,如果有不法分子在你项目中构造了一个java.lang.String类,并在该类中植入了一些不良代码,但你自己浑然不知,以为使用的String类还是 rt.jar 包下的,那可能会给你系统造成不良的影响。 聪明的Java虚拟机实现者也想到了这个问题,于是,他们引入了 双亲委派模型来解决这个问题。 下面是双亲委派模型的加载流程机制: 总结来说:双亲委派机制就是如果一个类加载器收到了类加载请求,它首先不会自己尝试去加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父类加载器反馈到无法完成这个加载请求(它的搜索范围没有找到这个类),子加载器才会尝试自己去加载。 其实,这里叫双亲委派可能有点不妥,因为按道理来讲只有父加载器,这里的“双亲”是“parents”的直译,并不表示汉语中的父母双亲。另外,这里的父加载器也不是继承的关系。 回到上面提出的问题,如果你自定义了一个 java.lang.String类,你会发现这个自定义的String.java可以正常编译,但是永远无法被加载运行。因为加载这个类的加载器,会一层一层的往上推,最终由启动类加载器来加载,而启动类加载的会是源码包下的String类,不是你自定义的String类。 3、自定义类加载器 先说说我们为什么要自定义类加载器? ①、加密 我们知道Java字节码是可以进行反编译的,在某些安全性高的场景,是不允许这种情况发生的。那么我们可以将编译后的代码用某种加密算法进行加密,加密后的文件就不能再用常规的类加载器去加载类了。而我们自己可以自定义类加载器在加载的时候先解密,然后在加载。 ②、动态创建 比如很有名的动态代理。 ③、从非标准的来源加载代码 我们不用非要从class文件中获取定义此类的二进制流,还可以从数据库,从网络中,或者从zip包等。 明白了为什么要自定义类加载器,接下来我们再来详述如何自定义类加载器。 通过第 3 小节的 java.lang.ClassLoader 类的源码分析,类加载时根据双亲委派模型会先一层层找到父加载器,如果加载失败,则会调用当前加载器的 findClass() 方法来完成加载。因此我们自定义类加载器,有两个步骤: 1、继承 ClassLoader 2、覆写 findClass() 方法 Java虚拟机详解(七)------双亲委派机制 标签:main 二进制流 自己的 并且 自定义 字节码 详细 string类 源码 原文地址:https://www.cnblogs.com/zsy-code/p/13657971.html
启动类加载器无法被Java程序直接引用。
上一篇:Java:equals方法详解
下一篇:python tgz包安装
文章标题:Java虚拟机详解(七)------双亲委派机制
文章链接:http://soscw.com/index.php/essay/68631.html