ClassLoader.getSystemClassLoader() 系统类加载器,即Application ClassLoader,用于加载ClassPath下的类,采用双亲委派模型。

Thread.currentThread().getContextClassLoader() 线程上下文类加载器,用于解决基础类访问子类的问题。

getClass().getClassLoader() 当前类的类加载器。

在详细说下类加载器:

类加载器的层次结构

“横看成岭侧成峰”,站在Java虚拟机角度看,只存在2种不同类型的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器是C++实现的,是虚拟机自身一部分;另外一种是其他类加载器,这种类加载器都是虚拟机外部的,由Java实现,并且全部继承自抽象类java.lang.ClassLoader。站在Java程序员角度看,可以分成以下3种:启动类加载器,上面刚提到过,负载加载存放在JAVA_HOME/lib路径中的类或者被-Xbootclasspath参数所指定路径下的类。启动类加载器无法被Java程序直接引用。

扩展类加载器(Extension ClassLoader),这个加载器由sum.misc.Launcher$ExtClassLoader实现,负责加载JAVA_HOME/lib/ext路径下的类,或者由java.ext.dirs系统变量所指定下的类库。

应用程序类加载器(Application ClassLoader),这个类加载器由sum.misc.Launcher$AppClassLoader来实现。由于这个类加载器可以由ClassLoader.getSystemClassLoader()获取,因此也叫系统类加载器。AppClassLoader复杂加载用户类路径(ClassPath)上指定的类库,开发者可以直接使用。

以下是类加载器的层次结构

双亲委派模型

类加载器双亲委派模型是JDK1.2引入被应用于几乎所有的Java程序中。但它并不是一个强制性的约束模型,二是Java设计者推荐的一种类加载方式。

双亲委派有他的适用场景(它能够适用于绝大多数场景),模型可以保证Java程序的稳定运行,防止重复加载和任意修改。那具体是如何做到的呢?

双亲委派模型的工作过程如下:如果一个类加载器收到了类加载的请求,它首先不会自己尝试加载这个类,而是把请求委派给父类加载器去完成,如上图所示,每一层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有父类反馈自己无法完成这个加载请求时(即它的搜索范围没有找到指定的类),字加载器才会尝试自己加载。

比如java.lang.Object,无论哪个类加载器需要加载这个类,最终都由Bootstrap ClassLoader加载,因此Object在程序的各个类加载器环境都是同一个类。相反,如果如果不用双亲委派模型进行加载,用户自定义了一个Object类并放置在类路径下,最终可能会引发程序混乱。

双亲委派模型很好地解决了基础类的统一问题,保证了虚拟机的安全性。

非双亲委派模型

线程上下文类加载器

双亲委派模型适用于大部分场景,但也有它自身的缺陷,假设基础类由Bootstrap类加载器加载,但是基础类需要回调用户的代码,基础代码却是由应用类加载器加载,这个时候该怎么办呢?

JNDI(Java Naming and Directory Interface)服务就是上面描述的这种场景,JNDI是Java的标准服务,它自身的代码由Bootstrap类加载器加载,由于JNDI的目的就是对资源进行集中管理和查找,它需要调用独立厂商实现的JNDI接口提供者(SPI)的代码,独立厂商提供的代码jar包放置在ClassPath下,如果使用双亲委派模型加载类的方式是搞不定的,怎么办呢?

为了解决这个困境,Java设计团队引入了线程上下文类加载器(Thread Context ClassLoader),虽然它确实不太优雅,但解决问题啊。这个类加载器可以通过java.lang.Thread类的setContextClassLoader()方法进行设置,如果创建线程还未设置,它将从父线程中继承一个,如果在应用程序的全局范围内都没有设置过,那么这个类加载器就是AppClassLoader。有了线程上下文类加载器,JNDI服务就可以加载所需要的SPI代码,即父类加载器可以请求子类加载器完成类加载动作,这其实是违反了双亲委派原则的。实际上JNDI、JDBC、JCE、JAXB、JBI等所有涉及SPI加载动作的基本都采取的这种方式。

总结:线程上下文加载器之所以打破双亲委派模型是因为双亲委派模型依赖的单一方向的,并不能解决父类加载器去依赖子类加载器这种逆方向需求。

Tomcat类加载器

实际上,不只是Driver驱动的实现是这样,只要有需要,在双亲委派机制无法满足需求前提下,在tomcat、spring等等的容器框架也是通过一些手段绕过双亲委派机制。

双亲委派模型要求除了顶层的启动类加载器之外,其余的类加载器都应当由自己的父类加载器加载。tomcat 为了实现隔离性,没有遵守这个约定,每个webappClassLoader加载自己的目录下的class文件,不会传递给父类加载器。如下图所示

从图中的委派关系中可以看出:CommonClassLoader能加载的类都可以被Catalina ClassLoader和SharedClassLoader使用,从而实现了公有类库的共用。

CatalinaClassLoader和Shared ClassLoader自己能加载的类则与对方相互隔离。

WebAppClassLoader可以使用SharedClassLoader加载到的类,但各个WebAppClassLoader实例之间相互隔离。

JasperLoader的加载范围仅仅是这个JSP文件所编译出来的那一个.Class文件,它出现的目的就是为了被丢弃:当Web容器检测到JSP文件被修改时,会替换掉目前的JasperLoader的实例,并通过再建立一个新的Jsp类加载器来实现JSP文件的HotSwap功能。

总结:tomcat之所以破坏双亲委派模型,我想主要在于双亲委派模型只看到了共享性,没有看到隔离性需求,即共享是有条件的共享。

OSGI类加载器

非双亲委派模型的另一种需求来自程序动态性追求。比如代码热替换(HotSwap)、模块热部署(Hot Deployment)。可以哪USB热插拔技术来做比方。热部署对生产系统来说具有很大吸引力,不用停机就能完成部署效率啊。

OSGI是Java模块化标准,OSGI实现模块热部署的关键是它自定义的类加载器,每一个模块都有一个自己定义的类加载器,当需要更换一个Bundle时,则把Bundle连同类加载器一同替换以实现热替换。

在OSGI环境下,类加载器不再是树型结构的双亲委派模型,而是网状结构,当收到类加载请求时,OSGI是按照下面顺序进行类搜索的:以“java.*”开头的类,委派给父类加载器加载。

将委派列表名单内的类,委派给父类加载器加载。

将Import列表中的类,委派给Export这个类的Boundle的类加载器加载。

查找当前Boundle的ClassPath,使用自己的类加载器加载。

查找类是否在Fragment Boundle中,如果在,则委派给Fragment Boundle类加载器加载。

查找Dynamic Import列表的Boundle,委派给对应的Boundle类加载器加载。

如果以上都未查询到,则查找失败。

上面的搜索顺序除了1,2两点和双亲委派类似,其余都是平级类加载过程。

总结:OSGI Boundle类加载器提供了类加载的另一种机制,加载器结构不一定非得是树型结构,也可以是网状结构。

java类加载器有几种_请问这几种类加载器有什么区别?相关推荐

  1. python的装饰器很有用吗_你真的了解python装饰器么

    合理使用装饰器可以简化开发,并且使得代码更加清晰.下面我们分别介绍两种装饰器,不带参数的装饰器和带参数的装饰器. 一.不带参数的装饰器 我们用一个实际的例子来引入装饰器的概念,比如我们现在有一个方法A ...

  2. java编译后生成字节码_请问java源文件编译后怎么生成字节码文件?

    比如,有的java源程序生成一个字节码文件,带有内部类的生成两个.可是有一种情况怎么回事呢?importjava.awt.*;importjavax.swing.*;importjava.awt.ev ...

  3. java鼠标事件获得键盘值_请问JAVA怎么模拟鼠标和键盘事件[200分]

    比如要求模拟鼠标在左下角的[开始]上点一下 多谢 | 看看java.awt.Robot这个类,可能对你有帮助 Class Robot This class is used to generate na ...

  4. java不同类间调用数组_请问:JAVA中两个类中的方法都需要调用另一个类的数组进行对数组的初始化和调用。...

    匿名用户 1级 2013-09-14 回答 import java.util.ArrayList; import java.util.Iterator; import java.util.List; ...

  5. java 判断请求为 ajax请求_请问如何判断一个请求是不是ajax请求?

    针对跨域情况的getjson 或者ajax(jsonp)可以使用ACCEPT请求头部格式来判断 PHP端对应$_SERVER['HTTP_ACCEPT'] jsonp的请求一般是:text/javas ...

  6. 在java项目中咋样测试接口_请问java程序的接口中的测试类该怎么写?有什么用呢?...

    可使用android自带的httpclient框架实现. 1. GET 方式传递参数 //先将参数放入List,再对参数进行URL编码 List params = new LinkedList(); ...

  7. python分几种_python有几种类型?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 大体上把Python中的数据类型分为如下几类: Number(数字) 包括int,long,float,complex String(字符串) 例如:he ...

  8. 后羿采集器怎么导出数据_推荐爬虫神器后羿采集器,小白也能一键采集数据

    你有没有烦恼过,如何将网页中包含的各种信息转变为有用的数据呢? 粘贴复制??太累 开发软件??太贵 写python爬虫??太难学 下载了一些工具??太难用 这里推荐第2款采集数据的神器,后羿采集器,无 ...

  9. 常用的分隔符有哪三种_掌握这三种调漂方法,你想怎么钓就怎么钓,再也不用求人...

    调漂对于刚学钓鱼的钓友来说是一件非常头痛的事情,每次钓鱼大部分时间都浪费在调漂上,总是感觉调不好,不是灵了就是钝了!那么问题到底出在哪呢?今天就和大家分享三种针对悬坠钓的调漂方法,看懂弄明白了,再也不 ...

  10. 弱加密算法有哪几种_常见的几种加密方法

    常见的几种加密方法和实 常见的几种加密方法 : MD5 SHA1 RSA AES DES 1.MD5加密 是HASH算法一种. 是生成32位的数字字母混合码. MD5主要特点是 不可逆 MD5算法还具 ...

最新文章

  1. APS如何入门1-综述
  2. 【Python】Python 远程连接服务器,用它就够了
  3. 最小栈—leetcode155
  4. Ruby on Rails 终极部署方案 nginx+mina+puma
  5. 1020. 月饼 (25)-PAT乙级真题
  6. apache poi处理表格示例
  7. atitit.交换机 汇聚上联、网络克隆和标准共享的原理与区别
  8. 坚持开源、能力内化,中移苏研荣获“中国开源领军企业”大奖!
  9. 【NOIP2016提高组】蚯蚓
  10. jconsole使用
  11. mbedtls 自带SSL demo调试
  12. 华为硬件工程师社招机考题库_华为硬件工程师笔试题
  13. 文件夹变exe怎么办
  14. 天馈线测试仪是什么?
  15. 制造业质量管理四大病因
  16. Web前端js实现tif文件浏览(含多页tif)
  17. stm32mp157开发板MIC 接口测试方法
  18. 在虚幻引擎中使用Python批处理4_:贴图参数设置
  19. 新书推荐 |《机器学习:算法视角(原书第2版)》
  20. 网页中常用的js特效

热门文章

  1. TCL语言语法简介(上)
  2. Ubuntu14.04安装PyV8--学习笔记
  3. Android聊天软件开发(基于网易云IM即时通讯)——添加好友(三)
  4. 一只Quant菜鸟的修行之路
  5. 索宝机器人_这些莞味十足的旅游商品获奖了!你尝过没?
  6. JSONP 的工作原理
  7. python实现文本翻译
  8. 登入ftp:500 OOPS: vsf_sysutil_bind, maximum number of attempts to find a listening port exceeded
  9. 自然语言处理技术的一些应用
  10. 安卓音量设置流程之MasterVolume