Java基础—ClassLoader的理解(转)
默认的三个类加载器
Java默认是有三个ClassLoader,按层次关系从上到下依次是:
- Bootstrap ClassLoader
- Ext ClassLoader
- System ClassLoader
Bootstrap ClassLoader是最顶层的ClassLoader,它比较特殊,是用C++编写集成在JVM中的,是JVM启动的时候用来加载一些核心类的,比如:rt.jar,resources.jar,charsets.jar,jce.jar等,可以运行下面代码看都有哪些:
URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();for (int i = 0; i < urls.length; i++) {System.out.println(urls[i].toExternalForm());}
file:/C:/Program%20Files/Java/jre6/lib/resources.jar
file:/C:/Program%20Files/Java/jre6/lib/rt.jar
file:/C:/Program%20Files/Java/jre6/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jre6/lib/jsse.jar
file:/C:/Program%20Files/Java/jre6/lib/jce.jar
file:/C:/Program%20Files/Java/jre6/lib/charsets.jar
file:/C:/Program%20Files/Java/jre6/lib/modules/jdk.boot.jar
file:/C:/Program%20Files/Java/jre6/classes
其余两个ClassLoader都是继承自ClassLoader这个类。Java的类加载采用了一种叫做“双亲委托”的方式(稍后解释),所以除了Bootstrap ClassLoader其余的ClassLoader都有一个“父”类加载器, 不是通过集成,而是一种包含的关系。
//ClassLoader.javapublic abstract class ClassLoader {...// The parent class loader for delegationprivate ClassLoader parent;...
“双亲委托”
所谓“双亲委托”就是当加载一个类的时候会先委托给父类加载器去加载,当父类加载器无法加载的时候再尝试自己去加载,所以整个类的加载是“自上而下”的,如果都没有加载到则抛出ClassNotFoundException异常。
上面提到Bootstrap ClassLoader是最顶层的类加载器,实际上Ext ClassLoader和System ClassLoader就是一开始被它加载的。
Ext ClassLoader称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目录下的所有的jar(包括自己手动放进去的jar包)。
System ClassLoader叫做系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件,包括我们平时运行jar包指定cp参数下的jar包。
运行下面的代码可以验证上面内容:
ClassLoader loader = Debug.class.getClassLoader();while(loader != null) {System.out.println(loader);loader = loader.getParent();}System.out.println(loader);
sun.misc.Launcher$AppClassLoader@addbf1
sun.misc.Launcher$ExtClassLoader@42e816
null
“双亲委托”的作用
之所以采用“双亲委托”这种方式主要是为了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如String,同时也避免了重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类,如果相互转型的话会抛java.lang.ClassCaseException.
自定义类加载器
除了上面说的三种默认的类加载器,用户可以通过继承ClassLoader类来创建自定义的类加载器,之所以需要自定义类加载器是因为有时候我们需要通过一些特殊的途径创建类,比如网络。
至于自定义类加载器是如何发挥作用的,ClassLoader类的loadClass方法已经把算法定义了:
protected synchronized Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{// First, check if the class has already been loadedClass c = findLoadedClass(name);if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.c = findClass(name);}}if (resolve) {resolveClass(c);}return c;}
>1. Invoke findLoadedClass(String) to check if the class has already been loaded.
>2. Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
>3. Invoke the findClass(String) method to find the class.
看上面的Javadoc可以知道,自定义的类加载器只要重载findClass就好了。
Context ClassLoader
首先Java中ClassLoader就上面提到的四种,Bootstrap ClassLoader,Ext ClassLoader,System ClassLoader以及用户自定义的,所以Context ClassLoader并不是一种新的类加载器,肯定是这四种的一种。
首先关于类的加载补充一点就是如果类A是被一个加载器加载的,那么类A中引用的B也是由这个加载器加载的(如果B还没有被加载的话),通常情况下就是类B必须在类A的classpath下。
但是考虑多线程环境下不同的对象可能是由不同的ClassLoader加载的,那么当一个由ClassLoaderC加载的对象A从一个线程被传到另一个线程ThreadB中,而ThreadB是由ClassLoaderD加载的,这时候如果A想获取除了自己的classpath以外的资源的话,它就可以通过Thread.currentThread().getContextClassLoader()来获取线程上下文的ClassLoader了,一般就是ClassLoaderD了,可以通过Thread.currentThread().setContextClassLoader(ClassLoader)来显示的设置。
为什么要有Contex ClassLoader
之所以有Context ClassLoader是因为Java的这种“双亲委托”机制是有局限性的:
- 举网上的一个例子:
> JNDI为例,JNDI的类是由bootstrap ClassLoader从rt.jar中间载入的,但是JNDI具体的核心驱动是由正式的实现提供的,并且通常会处于-cp参数之下(注:也就是默认的System ClassLoader管理),这就要求bootstartp ClassLoader去载入只有SystemClassLoader可见的类,正常的逻辑就没办法处理。怎么办呢?parent可以通过获得当前调用Thread的方法获得调用线程的>Context ClassLoder 来载入类。
- 我上面提到的加载资源的例子。
Contex ClassLoader提供了一个突破这种机制的后门。
Context ClassLoader一般在一些框架代码中用的比较多,平时写代码的时候用类的ClassLoader就可以了。
参考链接
http://www.cnblogs.com/magialmoon/p/3952445.html
Java基础—ClassLoader的理解(转)的更多相关文章
- Java基础—ClassLoader的理解
##默认的三个类加载器 Java默认是有三个ClassLoader,按层次关系从上到下依次是: - Bootstrap ClassLoader - Ext ClassLoader - System C ...
- java的classLoader原理理解和分析
java的classLoader原理理解和分析 学习了:http://blog.csdn.net/tangkund3218/article/details/50088249 ClassNotFound ...
- Java 基础:认识&理解关键字 native 实战篇
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 泥瓦匠初次遇见 navicat 是在 java.lang.Object 源码中的一个hashCode方 ...
- Java基础之深入理解Class对象与反射机制
深入理解Class对象 RRIT及Class对象的概念 RRIT(Run-Time Type Identification)运行时类型识别.在<Thinking in Java>一书第十四 ...
- Java基础系列-深入理解==和equals的区别(一)
一.前言 说到==和equals的问题,面试的时候可能经常被问题到,有时候如果你真的没有搞清楚里边的原因,被面试官一顿绕就懵了,所以今天我们也来彻底了解一下这个知识点. 二.==和equals的作用 ...
- java基础强化——深入理解反射
目录 1.从Spring容器的核心谈起 2. 反射技术初探 2.1 什么是反射技术 2.2 类结构信息和java对象的映射 3 Class对象的获取及需要注意的地方 4. 运行时反射获取类的结构信息 ...
- java基础强化——深入理解java注解(附简单ORM功能实现)
目录 1.什么是注解 2. 注解的结构以及如何在运行时读取注解 2.1 注解的组成 2.2 注解的类层级结构 2.3 如何在运行时获得注解信息 3.几种元注解介绍 3.1 @Retention 3.2 ...
- Java基础-四大特性理解(抽象、封装、继承、多态)
抽象: 象就是有点模糊的意思,还没确定好的意思. 就比方要定义一个方法和类.但还没确定怎么去实现它的具体一点的子方法,那我就可以用抽象类或接口.具体怎么用,要做什么,我不用关心,由使用的人自己去定义去 ...
- [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!
java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方. synchronized关键字涉及到锁的概念, 在java中,synchronized ...
随机推荐
- 【iOS技术】Xcode+GitHub远程代码托管(GIT, SVN)
原创 2016-05-24 旭哥 蓝鸥 学生对旭哥的评价是这样的: 旭哥 为什么这么年轻 知识却比我们多这么多............ 旭哥很是负责,对同学的各种问题都能够热心地解答,在旭哥的带领下, ...
- “-="的陷阱
1.有如下代码(显示下拉框时,屏幕最大化右键菜单的显示坐标处理): 起初: Rectangle rect = System.Windows.Forms.SystemInformation.Virtua ...
- QF——网络之网络请求的几种方式,图片缓存
同步请求和异步请求: 同步请求会阻塞主线程:不会开启新的线程,还是主线程,所以直到请求成功后,才能执行其它操作. 异步请求不会阻塞主线程.开启新的线程去请求服务器,而不影响用户的交互操作等其他动作. ...
- Git 系列(四):在 Git 中进行版本回退
在这篇文章中,你将学到如何查看项目中的历史版本,如何进行版本回退,以及如何创建 Git 分支以便你可以大胆尝试而不会出现问题. 在你的 Git 项目的历史中,你的位置就像是摇滚专辑中的一个片段,由一个 ...
- CSS3 Pie工具可以让IE6至IE8版本实现大多数的CSS3修饰特性,如圆角、阴影、渐变等
css3 pie使用方法: <!doctype html> <html lang="en"> <head> <meta charset=& ...
- Web 前端知识点
- SQL Server 恢复过程
在恢复过程中.只会分析那些自最后一个检查点之后发生的更改,以确定是否需要重做还是撤销. 在最后一个检查点之前完成的操作都会精确的反应到数据文件中,恢复过程不需要做其它的事. 第一阶段: 分析. 这个阶 ...
- [Drools]JAVA规则引擎 -- Drools 2
上一篇文章 http://blog.csdn.net/quzishen/archive/2011/01/25/6163012.aspx 描述了一些常用的drools的语法标签和一个模拟实例即发送积分的 ...
- WISPr1.0
王桢珍 王兵 侯志强 苑红 中国移动研究院 网络技术研究所, 北京100053 摘要 本文详细介绍了WLAN国际漫游的WISPr1.0技术规范并探讨其具体实现,包括基于WISPr1.0的WLAN国 ...
- Android NDK 编译FFmpeg(不需要复杂的环境变量设置)
环境: CentOS6.2——64位 借鉴:https://vec.io/posts/how-to-build-ffmpeg-with-android-ndk 在根目录下创建work文件夹:cd / ...