Java 类加载体系之 ClassLoader 双亲委托机制

java 是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是:

  • 类加载体系
  • .class文件检验器
  • 内置于java虚拟机的安全特性
  • 安全管理器及javaAPI

类的加载体系如下

java 程序中的 .java 文件编译完会生成 .class 文件,而 .class 文件就是通过被称为类加载器的 ClassLoader加载的,而 ClassLoder 在加载过程中会使用“双亲委派机制”来加载 .class 文件,先上图:

BootStrapClassLoader :启 动 类 加 载 器 ,该ClassLoader 是 jvm 在 启 动 时 创 建 的 ,用 于 加载$JAVA_HOME$/jre/lib 下面的类库(或者通过参数-Xbootclasspath 指定)。由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不能直接通过引用进行操作。

ExtClassLoader:扩展类加载器,该 ClassLoader 是在 sun.misc.Launcher 里作为一个内部类 ExtClassLoader 定义的(即 sun.misc.Launcher$ExtClassLoader),ExtClassLoader 会加载 $JAVA_HOME/jre/lib/ext 下的类库(或者通过参数-Djava.ext.dirs 指定)。

AppClassLoader:应用程序类加载器,该 ClassLoader 同样是在 sun.misc.Launcher 里作为一个内部AppClassLoader 定义的(即 sun.misc.Launcher$AppClassLoader),AppClassLoader 会加载 java 环境变量 CLASSPATH 所指定的路径 下的类库,而 CLASSPATH 所指定的 路 径 可 以 通 过System.getProperty("java.class.path")获取;当然,该变量也可以覆盖,可以使用参数-cp,例如:java -cp 路径 (可以指定要执行的 class 目录)。

CustomClassLoader:自定义类加载器,该 ClassLoader 是指我们自定义的 ClassLoader,比如 tomcatStandardClassLoader 属于这一类;当然,大部分情况下使用 AppClassLoader 就足够了。

前面谈到了 ClassLoader 的几类加载器,而 ClassLoader 使用双亲委派机制来加载 class 文件的。ClassLoader的双亲委派机制是这样的(这里先忽略掉自定义类加载器 CustomClassLoader):

1)当 AppClassLoader 加载一个 class 时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器 ExtClassLoader 去完成。

2)当 ExtClassLoader 加载一个 class 时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader 去完成。

3)如果 BootStrapClassLoader 加载失败(例如在$JAVA_HOME$/jre/lib 里未查找到该 class),会使用ExtClassLoader 来尝试加载;

4)若 ExtClassLoader 也加载失败,则会使用 AppClassLoader 来加载,如果 AppClassLoader 也加载失败,则会报出异常 ClassNotFoundException。

下面贴下 ClassLoader 的 loadClass(String name, boolean resolve)的源码:

1.protected synchronized Class<?> loadClass(String name, boolean resolve)
2.  throws  ClassNotFoundException  {
3. //  首先找缓存是否有 class
4. Class  c  =  findLoadedClass(name);
5. if  (c  ==  null)  {
6. //没有判断有没有父类
7. try  {
8. if  (parent  !=  null)  {
9. //有的话,用父类递归获取 class
10. c = parent.loadClass(name, false);
11. } else {
12. //没有父类。通过这个方法来加载
13. c = findBootstrapClassOrNull(name);
14. }
15. } catch (ClassNotFoundException e) {
16. // ClassNotFoundException thrown if class not found
17. // from the non-null parent class loader
18. }
19. if (c == null) {
20. //  如果还是没有找到,调用 findClass(name)去找这个类
21. c = findClass(name);
22. }
23. }
24. if (resolve) {
25. resolveClass(c);
26. }
27. return c;
28.  }

代码很明朗:首先找缓存(findLoadedClass),没有的话就判断有没有 parent,有的话就用 parent 来递归的 loadClass,然而 ExtClassLoader 并没有设置 parent,则会通过 findBootstrapClassOrNull 来加载 class,而findBootstrapClassOrNull 则会通过 JNI 方法”private native Class findBootstrapClass(String name)“来使用 BootStrapClassLoader 来加载 class。

然后如果 parent 未找到 class,则会调用 findClass 来加载 class,findClass 是一个 protected 的空方法,可以覆盖它以便自定义 class 加载过程。另 外 ,虽 然 ClassLoader 加载类是使用 loadClass 方法 ,但 是 鼓 励 用 ClassLoader 的 子 类 重 写 findClass(String),而不是重写 loadClass,这样就不会覆盖了类加载默认的双亲委派机制。

双亲委派托机制为什么安全

举个例子,ClassLoader 加载的 class 文件来源很多,比如编译器编译生成的 class、或者网络下载的字节码。而一些来源的 class 文件是不可靠的,比如我可以自定义一个 java.lang.Integer 类来覆盖 jdk 中默认的 Integer 类,例如下面这样:

1. package java.lang;
2. public class Integer {
3.   public Integer(int value) {
4.  System.exit(0);
5. }
6. }

初始化这个 Integer 的构造器是会退出 JVM,破坏应用程序的正常进行,如果使用双亲委派机制的话该 Integer 类永远不会被调用,以为委托 BootStrapClassLoader 加载后会加载 JDK 中的 Integer 类而不会加载自定义的这个,可以看下下面这测试个用例:

1.public static void main(String...  args) {
2. Integer i = new Integer(1);
3. System.err.println(i);
4.}

执行时 JVM 并未在 new Integer(1)时退出,说明未使用自定义的 Integer,于是就保证了安全性。

Java 类加载体系之 ClassLoader 双亲委托机制的更多相关文章

  1. java安全沙箱(一)之ClassLoader双亲委派机制

    java是一种类型安全的语言,它有四类称为安全沙箱机制的安全机制来保证语言的安全性,这四类安全沙箱分别是: 类加载体系 .class文件检验器 内置于Java虚拟机(及语言)的安全特性 安全管理器及J ...

  2. classLoader双亲委托与类加载隔离

    虽然前面把class文件的产生到加载使用流程说了一遍,但是还是想具体看看classLoader的双亲委托具体是如何运行的,有什么利弊. 还有想看看不同类加载器的不同命名空间带来那些好处和实际有那些应用 ...

  3. JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制

    代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...

  4. JVM 类加载器的双亲委托机制

    1.类加载器的层次结构 在双亲委托机制中,各个加载器按照父子关系形成了树形结构(逻辑意义),除了根加载器之外,其余的类加载器都有且只有一个父加载器. public class MyTest13 { p ...

  5. Java基础-类加载机制与自定义类Java类加载器(ClassLoader)

    Java基础-类加载机制与自定义类Java类加载器(ClassLoader) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于类加载器的概念和分类我就不再废话了,因为我在之前的笔 ...

  6. 破坏双亲委托机制的一些情况---Tomcat和JDBC,破坏后的安全问题

    采用双亲委托机制的原因 类加载器就是将字节码搬进jvm方法区的组件.我们知道,JVM识别加载进来的类是通过类加载器+类全名完成的,也就是说同一个类由不同类加载器加载进去的话就会被视为不同的类.jdk提 ...

  7. 【JVM学习笔记】双亲委托机制存在的意义

    1.可以确保Java核心库的类型安全:所有的Java应用都至少会引用java.lang.Object类,也就是说在运行期,java.lang.Object这个类会被加载到Java虚拟机:如果用户自定义 ...

  8. ClassLoader类加载器 & Java类加载机制 & 破坏双亲委托机制

    ClassLoader类加载器 Java 中的类加载器大致可以分成两类: 一类是系统提供的: 引导类加载器(Bootstrap classloader):它用来加载 Java 的核心库(如rt.jar ...

  9. java的类加载器体系结构和双亲委派机制

    类加载器将字节码文件加载到内存中,同时在方法区中生成对应的java.land.class对象  作为外部访问方法区的入口. 类加载器的层次结构: 引导类加载器<-------------扩展类加 ...

随机推荐

  1. Linux下安装&运行Jmeter程序

    Jmeter在linux系统中运行需要安装jdk和Jmeter两个软件: 1.安装JDK 先检查系统是否有安装jdk,在linux中执行如下命令:java -version  如果返回版本信息,说明系 ...

  2. python 基础内置函数表及简单介绍

    内建函数名 (表达形式) 主要作用 备注 abs(x) 返回一个X值得绝对值(x=int/float/复数) all(iterable) 如果 iterable 的所有元素均为 True(或 iter ...

  3. if else 选择机构 _多重if选择机构_if选择结构嵌套(综合练习题——code)

    import java.util.*; class If01{ public static void main(String[ ]args){ //练习1:假如张三参加Java考试,判断如果在95分以 ...

  4. numpy初用

    import numpy as np for k,v in stat.iteritems():     print k     v.sort()     #v = v[len(v)*3/100:len ...

  5. 大数据 Big Data howto

    The Fourth Paradigm: Data-Intensive Scientific Discovery http://research.microsoft.com/en-us/collabo ...

  6. 性能测试工具LoadRunner30-LR之监控Tomcat

    步骤: 1.通过LR去访问tomcat监控页(安装tomcat的过程可以百度一下) 2.然后通过关联取监控数据 3.通过lr_user_data_point()添加数据到图表中去 double ato ...

  7. [转]jQuery的.live()和.die()

    本文转自:http://www.cnblogs.com/dumuqiao/archive/2011/09/09/2172513.html 翻译原文地址:http://www.alfajango.com ...

  8. (转)Linux curl命令详解

    命令:curl在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具.它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具. ...

  9. SpringMVC restful风格

    1.Spring对REST的支持 Spring3(这里讨论Spring3.2+)对Spring MVC的一些增强功能为REST提供了良好的支持.Spring对开发REST资源提供以下支持: 操作方式: ...

  10. DEDE文章列表加上序号效果

    在文章列表上面加上序号列表的形式,使得文章列表表现得没那么单调,更加丰富一点. {dede:arclist orderby=pubdate type='commend.' titlelen='26' ...