java类加载器——ClassLoader
Java的设计初衷是主要面向嵌入式领域,对于自定义的一些类,考虑使用依需求加载原则,即在程序使用到时才加载类,节省内存消耗,这时即可通过类加载器来动态加载。
如果你平时只是做web开发,那应该很少会跟类加载器打交道,但如果你想深入学习tomcat服务器的架构,它是必不可少的。所谓类加载器,就是用于加载Java类到Java虚拟机中,它负责读取Java字节码,并转换成java.lang.Class类的一个实例,使字节代码.class文件得以运行。一般类加载器负责根据一个指定的类找到对应的字节代码,然后根据这些代码定义成一个Java类,另外还负责加载资源,包括图像文件和配置文件。
类加载器在实际使用中给我们带来的好处是,它可以使Java类动态地加载到JVM并运行,即可在程序运行时再加载类,提供了很灵活的动态加载方式。例如我们熟悉的Applet,从远程服务器下载字节码到客户端动态加载到JVM便可以运行。
在Java的庞大体系中,可以将系统分为三种类加载器,分别是:
① 启动类加载器(Bootstrap ClassLoader):加载对象是Java核心库,把一些关键的Java类加载进JVM,这个加载器使用原生代码(C/C++)实现的,并不是继承java.lang.ClassLoader,它是所有其他类加载器的最终父加载器,负责加载<JAVA_HOME>/jre/lib目录下且被JVM指定的类库,其实它属于JVM整体的一部分,JVM一启动就将这些指定的类加载到内存中,避免以后过多的I/O操作,提高系统的运行效率。启动类加载器无法被Java程序直接使用。
② 扩展类加载器(Extension ClassLoader):加载的对象为Java的扩展库,即加载<JAVA_HOME>/jre/lib/ext目录里面的类。这个类由上面的Bootstrap ClassLoader加载,但由于Bootstrap ClassLoader并非用Java实现,已经脱离了Java体系,所以如果尝试调用扩展类加载器的getParent()方法获取父加载器会得到null,但它的父类加载器是Bootstrap ClassLoader。Java中可以直接使用扩展类加载器。
③ 应用程序类加载器(Application ClassLoader):亦叫系统类加载器(System ClassLoader),它负责加载用户类路径(CLASSPATH)指定的类库,如果程序没有自己定义类加载器,就默认使用应用程序类加载器。它也由Bootstrap ClassLoader加载,但它的父加载类被设置成了Extension ClassLoader。如果要使用这个加载器,可通过ClassLoader.getSystemClassLoader()获取。
假如有一天你心血来潮也想自己写一个类加载器,那么你只需要继承java.lang.ClassLoader类即可。于是可以用下面的图2-4-1来清晰表示出各种类加载器的关系,Bootstrap ClassLoader是最根本的类加载器,其不存在父类加载器,Extension ClassLoader由Bootstrap ClassLoader加载,所以它的父类加载器是Bootstrap ClassLoader,Application ClassLoader也是由Bootstrap ClassLoader加载,但它的父加载器被指向了Extension
ClassLoader,而其他所有用户自定义的类加载器都由Application ClassLoader加载。
由此可以看出越重要的类加载器就越早被JVM载入,这是考虑到安全性,因为先加载的类加载器会充当下一个类加载器的父加载器,在双亲委派模型机制下,就能确保安全性。
那么什么是双亲委派模型?比如爷爷、爸爸、你三代单传,你们家族都遗传懒惰基因,每当遇到事情都互相推脱,现在需要一个人去买一包盐,不然今晚的菜就有色无味了,而你第一个被委托去超市买,但由于你的懒惰,你向你爸爸撒了一顿娇,你爸爸受不了你只能答应帮你去,在懒惰的驱使下,你爸爸最后找了一个借口说要赶工作,让你爷爷出去走动走动顺便买一包盐,就这样你爷爷只能乖乖去超市买盐。双亲委派模型就类似这样的机制,类加载器加载类时首先委托给父类加载器加载,除非父类加载器不能加载才自己加载。
这种模型要求除了顶层的启动类加载器外,其他的类加载器都要有自己的父类加载器。假如有一个类要加载进来,一个类加载器并不会马上尝试自己将其加载,而是委派到父类加载器,父类加载器收到后又尝试委派到其父类加载器,以此类推,直到委派到启动类加载器,这样一层一层往上委派。只有当父类加载器反馈自己没法完成这个加载时,子加载器才会尝试自己加载。通过这个机制,保证了Java应用所使用的都是同一个版本的Java核心库的类。同时这个机制也保证了安全性,设想如果Application ClassLoader想要加载一个有破坏性的java.lang.System类,双亲委派模型会一层层向上委派,最终委派给Bootstrap
ClassLoader,而Bootstrap ClassLoader检查到缓存中已经有了这个类,并不会再加载这个有破坏性的System类。
另外,类加载器还拥有全盘负责机制,即当一个ClassLoader加载一个类时,这个类所依赖的、引用的其他所有类都由这个ClassLoader加载,除非在程序中显性地指定另外一个ClassLoader加载。
图2-4-1 类加载器关系
在Java中,我们用完全匹配类名来标识一个类,即用包名和类名。而在JVM中,一个类由完全匹配类名和一个类加载器的实例ID作为唯一标识。即是说同一个虚拟机可以有两个包名、类名都相同的类,只要他们由两个不同类加载器加载。于是当我们在Java中经常说两个类相不相等,必须是针对同一个类加载器加载的前提下才有意义,否则就算是同样的字节代码,由不同类加载器加载,这两个类也不是相等的。这种特征为我们提供了隔离机制,在tomcat服务器中是十分有用的。
了解了JVM的类加载器的各种机制后,看看一个类是怎样被类加载器载入进来的。一个类准备加载,类加载器先判断此类是否已经被加载过(加载过的类会被缓存在内存中),如果缓存中存在此类则直接返回这个类。否则获取父类加载器,如果父类加载器为null,则由Bootstrap ClassLoader载入并返回Class。如果父类加载器不为null,则由父类加载器载入,载入成功就返回Class,载入失败则根据类路径查找class文件,找到就加载此class并返回Class,找不到就抛出ClassNotFoundException异常。
图2-4-2 类加载过程
类加载器属于JVM级别的设计,我们很多时候基本不会跟他打交道,但是假如你想了解整个JAVA体系是如何工作的,假如你要设计开发自己的框架或中间件或一个较庞大的java软件,那么你必须熟悉类加载器的相关机制,在现实的设计中,根据实际情况利用类加载器可以提供类库的隔离及共享,保证你的软件不同级别的逻辑分割程序不会互相影响,提供更好的安全性。
喜欢研究java的同学可以交个朋友,下面是本人的微信号:
java类加载器——ClassLoader的更多相关文章
- 深入理解Java类加载器(ClassLoader)
深入理解Java类加载器(ClassLoader) Java学习记录--委派模型与类加载器 关于Java类加载双亲委派机制的思考(附一道面试题) 真正理解线程上下文类加载器(多案例分析) [jvm解析 ...
- 深入理解Java类加载器(ClassLoader) (转)
转自: http://blog.csdn.net/javazejian/article/details/73413292 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Ja ...
- Java 类加载器(ClassLoader)
类加载器 ClassLoader 什么是类加载器? 通过一个类的全限定名来获取描述此类的二进制字节流这个动作放到Java虚拟机外部去实现, 以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代 ...
- 浅析java类加载器ClassLoader
作为一枚java猿,了解类加载器是有必要的,无论是针对面试还是自我学习. 本文从JDK提供的ClassLoader.委托模型以及如何编写自定义的ClassLoader三方面对ClassLoader做一 ...
- 潜水 java类加载器ClassLoader
类加载器(class loader)用于装载 Java 类到 Java 虚拟机中.一般来说.Java 虚拟机使用 Java 类的方式例如以下:Java 源程序(.java 文件)在经过 Java 编译 ...
- Java类加载器ClassLoader总结
JAVA类装载方式,有两种: 1.隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中. 2.显式装载, 通过class.forname()等方法,显 ...
- Java类加载器(ClassLoader)
类加载的机制的层次结构 每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Jav ...
- Java类加载器(死磕5)
Java类加载器( CLassLoader ) 死磕5: 自定义一个文件系统classLoader 本小节目录 5.1. 自定义类加载器的基本流程 5.2. 入门案例:自定义文件系统类加载器 5 ...
- Java类加载器( 死磕9)
[正文]Java类加载器( CLassLoader ) 死磕9: 上下文加载器原理和案例 本小节目录 9.1. 父加载器不能访问子加载器的类 9.2. 一个宠物工厂接口 9.3. 一个宠物工厂管理 ...
随机推荐
- mysql之查询
#数据准备drop table if exists class;create table class( class_no int(2) unsigned zerofill primary key ...
- Codeforces Round #460 E. Congruence Equation
Description 题面 \(n*a^n≡b (\mod P),1<=n<=x\) Solution 令 \(n=(P-1)*i+j\) \([(P-1)*i+j]*a^{[(P-1) ...
- ●POJ 1228 Grandpas Estate
题链: http://poj.org/problem?id=1228 题解: 计算几何,凸包 题意:给出一些点,求出其凸包,问是否是一个稳定的凸包. 稳定凸包:不能通过新加点使得原来凸包上的点(包括原 ...
- qemu 模拟-arm-mini2440开发板-启动u-boot,kernel和nfs文件系统【转】
转自:http://www.cnblogs.com/riskyer/p/3366001.html qemu 本文介绍了如何编译u-boot.linux kernel,然后用qemu启动u-boot和l ...
- PHP中利用DOM和simplxml读取xml文档
实例 用DOM获取下列xml文档中所有金庸小说的书名,该xml文档所在位置为 ./books.xml: <?xml version="1.0" encoding=" ...
- C语言第三次程序设计作业
(一)改错题 计算f(x)的值:输入实数x,计算并输出下列分段函数f(x)的值,输出时保留1位小数. 1)源程序(有错误的程序) #include <stdio.h> int main(v ...
- DS4700磁盘阵列的控制器微码升级操作记录(收录百度文库)
DS4700磁盘阵列的控制器微码升级操作记录 项目介绍: 于10年3月,XX地市区/州XX分公司相继反映生产读取数据速度较之前变得非常慢,表现在:日常报表抽取数据速度明显变慢,客户打开前台页面速度 ...
- c# 虚拟路径转化为物理路径
string strPhycicsPath= Server.MapPath(path);
- 在Spring Boot中使用Spring Security实现权限控制
丢代码地址 https://gitee.com/a247292980/spring-security 再丢pom.xml <properties> <project.build.so ...
- 开发网页时,127.0.0.1或者localhost能访问,而本机地址不能访问的解决
第一 ping试试 127.0.0.1 和 本机地址 若127.0.0.1可以 说明可以自己ping自己 若本机地址可以 说明host正常 第二 检查服务器部署 再部署一个新的 若新的正常 说明你项目 ...