文档章节

深入探讨Java类加载器

ericquan8
 ericquan8
发布于 2015/02/20 00:32
字数 1081
阅读 1210
收藏 99

    本篇文章主要是详细写一下个人对Java ClassLoader的理解。

    首先回顾一下,java虚拟机载入java类的步骤:java文件经过编译器编译后变成字节码文件(.class文件),类加载器(ClassLoader)读取.class文件,并且转换成java.lang.Class的一个实例,最后通过newInstance方法创建该类的一个对象。ClassLoader的作用就是根据一个类名,找到对应的字节码,根据这些字节码定义出对应的类,该类就是java.lang.Class的一个实例。


类加载器的组织结构

    java有三个初始类加载器,当java虚拟机启动时,它们会按照以下顺序启动:bootstrap classloader -> extension classloader -> system classloader。三者的关系:bootstrap classloader是extension classloader的parent,extension classloader是system classloader的parent。

bootstrap classloader

    它是最原始的类加载器,并不是由java代码写的,是由原生代码编写的。Java有一次编译、所有平台运行的效果,就是因为它写了一份功能相同,但针对不同平台不同语言实现的底层代码。它负责加载java核心库,大家可运行以下代码,看看自己本地的java核心库在哪里:

URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for (int i = 0; i < urls.length; i++) {
	System.out.println(urls[i].toExternalForm());
}

本人的运行结果:

file:/home/eric/jdk1.6.0_35/jre/lib/resources.jar
file:/home/eric/jdk1.6.0_35/jre/lib/rt.jar
file:/home/eric/jdk1.6.0_35/jre/lib/sunrsasign.jar
file:/home/eric/jdk1.6.0_35/jre/lib/jsse.jar
file:/home/eric/jdk1.6.0_35/jre/lib/jce.jar
file:/home/eric/jdk1.6.0_35/jre/lib/charsets.jar
file:/home/eric/jdk1.6.0_35/jre/lib/modules/jdk.boot.jar
file:/home/eric/jdk1.6.0_35/jre/classes

extension classloader

    它用来加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或java.ext.dirs系统属性指定的)JAR的类包。注意,因为它是bootstrap classloader加载的,所以当你运行:

ClassLoader extensionClassloader=ClassLoader.getSystemClassLoader().getParent();
System.out.println("the parent of extension classloader : "+extensionClassloader.getParent());

输出的是:the parent of extension classloader : null

system classloader

它用于加载classpath目录下的jar包,我们写的java类,一般都是由它加载,除非你自己制定个人的类加载器。


全盘负责委托机制

classloader加载类时,使用全盘负责委托机制,可以分开两部分理解:全盘负责,委托。

全盘负责机制:若类A调用了类B,则类B和类B所引入的所有jar包,都由类A的类加载器统一加载。

委托机制:类加载器在加载类A时,会优先让父加载器加载,当父加载器加载不到,再找父父加载器,一直找到bootstrap  classloader都找不到,才自己去相关的路径去寻找加载。以下是ClassLoader的源码:

protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    //从父加载器加载
		    c = parent.loadClass(name, false);
		} else {
		    //从bootstrap loader加载
		    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;
    }

举个例子,类加载器加载类A的过程:

1,判断是否已经加载过,在cache里面查找,若有,跳7;否则下一步

2,判断当前加载器是否有父加载器,若无,则当前为ext classloader,跳去4;否则下一步

3,请求父加载器加载该类,若加载成功,跳7;若不成功,即父加载器不能找到该类,跳2

4,请求jvm的bootstrap classloader加载,若加载成功,跳7;若失败,跳5

5,当前加载器自己加载,若成功,跳7;否则,跳6

6,抛出ClassNotFoundException

7,返回Class


编写自己的类加载器

    Java加载类的过程,实质上是调用loadClass()方法,loadClass中调用findLoadedClass()方法来检查该类是否已经被加载过,如果没有就会调用父加载器的loadClass(),如果父加载器无法加载该类,就调用findClass()来查找该类。

    所以我们要做的就是新建MyClassLoader继承java.lang.ClassLoader,重写其中的findClass()方法。主要是重新设计查找字节码文件的方案,然后调用definedClass来返回。

    本人写了一个demo,用自己的类加载器去加载指定java文件,且带有热部署效果,具体请查看以下url。

    Demo地址:http://git.oschina.net/ericquan8/hot-deploy


© 著作权归作者所有

共有 人打赏支持
ericquan8
粉丝 6
博文 17
码字总数 21301
作品 0
广州
程序员
结合JVM源码谈Java类加载器

一、前言 之前文章 Java 类加载器揭秘 从Java层面讲解了Java类加载器的原理,这里我们结合JVM源码在稍微深入讲解下。 二、Java类加载器的委托机制 Java 类加载器使用的是委托机制,也就是一个...

阿里加多
04/29
0
0
JVM 虚拟机(对象创建,类加载器,执行引擎等),

1.揭开 Java 对象创建的奥秘? 2.class 文件结构详解? 3.详解 Java 类的加载过程? > Java 对象创建,class 文件结构 Java对象模型 。Java对象保存在堆内存中。在内存中,一个Java对象包含三...

desaco
08/29
0
0
简述 Java EE 容器的类加载,以及 JBoss AS 7 的特殊之处

既然是简述,就说的简单一点了,因为 Java 的类加载是一个很大的话题。很多技术,例如 Java EE 容器、OSGi 容器、JVM 上面的动态语言,都有自己在类加载上的特殊之处。 JVM 的类加载 先回顾一...

编走编想
2013/08/06
0
0
面试中关于Java虚拟机(jvm)的问题看这篇就够了

最近看书的过程中整理了一些面试题,面试题以及答案都在我的文章中有所提到,希望你能在以问题为导向的过程中掌握虚拟机的核心知识。面试毕竟是面试,核心知识我们还是要掌握的,加油~~~ 下面...

snailclimb
05/12
0
0
【JVM】浅谈双亲委派和破坏双亲委派

一、前言 笔者曾经阅读过周志明的《深入理解Java虚拟机》这本书,阅读完后自以为对jvm有了一定的了解,然而当真正碰到问题的时候,才发现自己读的有多粗糙,也体会到只有实践才能加深理解,正...

joemsu
07/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

造谣造到t-io老巢了

只发当事人的截图,不发表评论,以免有引导嫌疑 PS1:截图是由不同的人发过来的 PS2:本人已经不在此微信群 PS3:图3是2018-09-23的t-io官方群的一个发言小统计,有助于让人认识到他们的其中...

talent-tan
17分钟前
24
0
heartbeat 资源

drbd+apache+heartbeat : http://blog.51cto.com/11838039/1827901 heartbeat双机热备的架设 : http://blog.51cto.com/11838039/1827560 对heaetbeat的深一步认识 : http://blog.51cto.co......

寰宇01
51分钟前
3
0
Spring 转换 model 为 json 时增加属性

缘起 目前的项目中有个需求是在附件对象转换成 json 时增加个 url 属性,以前的方式是在返回附件对象或列表时候做一次统一处理,这次想看看 spring 或者 jackson fasterxml 是否自带类似功能...

郁也风
今天
3
0
10大PHP比特币开源项目

如果你是一个Phper,如果你希望学习区块链,那么本文列出的 10个开源的Php比特币项目,将有助于你了解在自己的应用中 如何加入对比特币的支持。 如果你希望快速掌握使用Php对接比特币钱包的方...

汇智网教程
今天
3
0
springclould feign客户端添加全局参数

用springclould feign作为调用服务的客户端,一般来说参数可以写在feignclient的方法参数里 有时需要所有feign请求都统一添加一些参数,例如token用于鉴权等,可以这样做: 添加一个配置类,...

canneljls
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部