文档章节

classLoader

mrliuze
 mrliuze
发布于 2015/04/28 16:59
字数 2537
阅读 6
收藏 0
点赞 0
评论 0
Java 中类的加载过程 (如 Dog 类):

 

1.       通过类型信息定位Dog.class文件。

2.       载入Dog.class文件,创建相应的Class对象。

3.       执行父类的静态字段定义时初始化语句和父类的静态初始化块。

4.       执行子类的静态字段定义时初始化语句和子类的静态初始化块。

5.       当使用new Dog()方式时,在堆上为Dog对象分配存储空间,并清零分配的存储空间。

6.       执行父类的字段定义时初始化语句和父类的构造函数。

7.       执行子类的字段定义时初始化语句和子类的构造函数。

(参考Java编程思想,部分是自己测试的结果,还没有看到相关资料,这个顺序和C#的顺序好像有比较大的差别)

 

我们知道每个Java类编译后会生成一个.class文件,里面除了存储了类的字节码之外,还存储了和该类对应的Class对象的信息(包含一些用于反射的信息)。在JVM中,通过类加载器(ClassLoader)来实现Class对象的创建。

 

Object类中有publicgetClass()方法,我们可以通过该方法获取与之对应的Class对象。在获取类对应的Class对象后,我们就可以通过newInstance()方法或者通过获取其Constructor的方法来创建该类的实例,也可以通过Class对象获取类或实例相关的更多信息,如方法,字段等,即反射的功能。另外我们也可以通过Class.forName()方法,通过传入类字符串的方式来创建类的实例。(通过Class对象创建类实例和通过forName方法创建类实例是否有联系呢?这两种创建类的实例和直接通过new创建类实例是否也有联系呢?

 

然而Dog.class文件是如何定位的?Dog.class文件是如何被加载并解析的?Class对象又是如何生成的呢?这就是ClassLoader需要解决的问题,也是这篇文章中接下来要讲述的。

 

ClassLoader的工作原理

 

Java内部实现了三种类型的ClassLoaderBootstrap ClassLoaderExtension ClassLoader System ClassLoader。这三个ClassLoader通过parent形成一条单向链,其中Bootstrap处于链尾,而System ClassLoader处于链头。

 

Bootstrap ClassLoader

Bootstrap ClassLoader用于在启动JVM时加载类,以使JVM能正常工作,因而它是用Native代码实现的,最早被创建出来,处于最底层。

Bootstrap ClassLoader将搜索Java核心库(%JAVA_HOME%\jre\lib),如rt.jari18n.jar等,在这些核心库中包含了Java的核心类,即Bootstrap ClassLoader用于加载Java的核心类,包括java.langjava.io等包中的类。

 

Extension ClassLoader

Extension ClassLoader位于链的中间层,它将搜索特定的标准扩展目录。该标准扩展目录在不同的JVM实现中不一定相同,在sunJVM中,它是%JRE_HOME% \lib\ext,具体路径可以通过java.ext.dirs系统属性值获取。该标准扩展目录存在的目的在于扩展和共享,应用程序厂商可以将部分共享库放置于此,而不是各自程序的目录下的多份拷贝。在开发过程中,我们也可以把部分常用的库放置于此,而不必每次都去配置环境。

 

System ClassLoader

System ClassLoader位于链的最顶层,它将搜索CLASSPATH中配置的目录和jar文件。

 

三种ClassLoader的协同工作

既然系统中有三种不同的ClassLoader,那么一个类的加载是用那个ClassLoader呢?在Java中,是通过“代理模型(delegation model)”来决定使用哪个ClassLoader来加载类的(读取.class文件,并创建相应的Class对象)。当一个类需要被加载的时候,系统默认通过System ClassLoader来加载该类;然而System ClassLoader并不立即加载该类,它会将加载的行为代理给其parent去加载,只有当其parent不能加载该类的时,System ClassLoader才去搜索CLASSPATH中的目录和jar文件以加载该类,若找到对应的.class文件,则加载该类,否则抛出ClassNotFoundException。当它将加载的行为代理给Extension ClassLoader并最终代理给Bootstrap ClassLoader的时候,他们也做的是相似的事情。从设计的角度,这其实就是一种职责链模式(Chain of Responsibility Pattern

 

那么Java为什么需要这种代理模型呢?答案是出于安全的考虑。Java是一种安全的编程语言,它会对每个加载的类执行安全检查,但是对Java核心库中的类是不执行安全检查的(即他们是受JVM信赖的)。(什么是安全检查?以我现在所知,就是用户可以通过security manager来控制特定目录的访问权限,如何使用这些控制将会是另一个主题。对安全检查是否还有其他的呢?)那么假如用户可以加载自己编写的和核心库同名的类(如java.lang.Object),那么这些用户编写的类就可以绕过安全检查,从而为一些恶意用户提供了一种破坏的途径。然而在使用这种代理模型后,类的加载首先会代理到Bootstrap ClassLoader中实行加载,如果它发现当前核心类库中可以加载对应的类,系统会加载核心库中的类,而不会加载用户编写的类。

 

但是如果只是这样,还不足以保证类的加载的安全。因为用户完全可以定义自己的ClassLoader,在自己的ClassLoader中破坏这种代理模型,那么用户自己写的java.lang.Object就可以被加载了。为了解决这个问题,在Java中认为两个类名相同的实例,如果加载他们的ClassLoader不同,那么他们是不同的类型,即他们之间不能转换,而且用instanceof操作符返回的是false。这样的话,即使用户加载了自己的java.lang.Object类,它也不是系统认为可以信赖的java.lang.Object,那么它就绕不过安全检查机制。(以上的描述只是我的猜想,我还没有看到相关的资料提到该问题,因而有待验证。)

 

有人说使用这种机制可以实现兼容性的升级,在软件的旧版本中使用某个旧版本的类,在升级的某些新部分中可以使用相同类的新版本,即实现内存中保留一个类的两个版本。我认为这种不应该是一种推荐的做法,在内存中保留一个类的两个版本极易在运行是引起一些莫名其妙的错误。

 

很可惜,我没能找到以上三种ClassLoader的源码,看不了内部的实现。在Java中,它们都是通过ClassLoader这个抽象类来表示的。以下简单的介绍一下ClassLoader内部的成员

(其中Extension ClassLoader的实现类为:sun .misc.Launcher$ExtClassLoader

 

ClassLoader类介绍

ClassLoader类位于java.lang包中,直接继承自Object,是一个抽象类。

 

两个构造函数(protected

一个带parent的参数,一个无参(默认用System ClassLoader作为其parent)。

 

静态方法

public static ClassLoader getSystemClassLoader()

获取System ClassLoader。可以通过设置系统属性:java.system.class.loader的值以修改该函数的返回类型(System.setProperty, System.getProperty)

 

public static URL getSystemResource(String name)

Resource是指数据,如图片、文本、音频等。我的理解Resource就是指在对应ClassLoader搜索路径(目录和jar文件内部)下的任何数据,包括文件和目录。那么该函数就是通过名字(目录名或文件名)返回资源所对应的URL值。(注:名字和返回中的目录分隔符都是用“/”来表示)。该函数的搜索顺序和.class文件的搜索顺序是一样的,所不同的是,用户自定义的ClassLoader可以通过重写public URL findResource(String name)方法来扩展该函数的搜索范围。

 

public static Enumeration<URL> getSystemResources(String name)

getSystemResource,只是它会返回多个URL的集合,用户自定义的ClassLoader可以通过public URL findResources(String name)来扩展该方法。

 

public static InputStream getSystemResourceAsStream(String name)

该函数内部通过调用getSystemResource()方法获取资源的URL地址,然后调用URL.openStream()方法获取资源的InputStream

 

public方法

public Class<?> loadClass(String name) throws ClassNotFoundException

protected synchronized Class<?> loadClass(String name, boolean resolve)

    throws ClassNotFoundException

通过类名加载类,在ClassLoader中,会缓存已加载的Class实例,因而该方法首先查询缓存中是否已经存在该类的Class实例。该方法实现了ClassLoader加载类的算法。JDK的表述,resolve是指链接(link)的意思,但是link又是指什么呢?这个我还清楚。用户自定义子类可以通过findClass()方法来扩展该方法。

 

public URL getResource(String name)

类似静态方法的getResource()方法。

 

public Enumeration<URL> getResources(String name)

类似静态方法的getResources()方法。

 

public final ClassLoader getParent()

如方法名。

 

public InputStream getResourceAsStream(String name)

类似静态方法的getResourceAsStream()方法

 

protected方法

protected URL findResource(String name)

getResource()的扩展方法,提供给子类重写。

 

protected Enumeration<URL> findResources(String name) throws IOException

getResources()的扩展方法,提供给子类重写。

 

protected Class<?> findClass(String name) throws ClassNotFoundException

loadClass()函数的扩展方法,该方法会在所有parent ClassLoader没有找到相应的类定义的时候调用,因而该方法只需要实现当前ClassLoader中需要额外搜索的路径即可。

 

protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,

       ProtectionDomain protectionDomain) throws ClassFormatError

protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError

protected final Class<?> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError

该方法用于将字节数组转化为相应的Class对象,在该Class对象使用前,该对象必须已经被解析了resolved or linked,同样,什么是解析或链接?)。可以指定ProtectionDomain,也可以使用默认的ProtectionDomain。子类在实现findClass()的时候可以调用该方法以将找到的.class二进制内容转化为Class实例。

本文转载自:http://dlevin.iteye.com/blog/772604

共有 人打赏支持
mrliuze
粉丝 11
博文 147
码字总数 11385
作品 0
浦东
程序员
图解classloader加载class的流程及自定义ClassLoader

java应用环境中不同的class分别由不同的ClassLoader负责加载。 一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职: Bootstrap Cl...

zhengguogaun ⋅ 2013/06/19 ⋅ 0

JDK中提供的ClassLoader

作为一枚java猿,了解类加载器是有必要的,无论是针对面试还是自我学习。 本文从JDK提供的ClassLoader、委托模型以及如何编写自定义的ClassLoader三方面对ClassLoader做一个简要的总结。 1....

281824088 ⋅ 2016/04/08 ⋅ 0

用ClassLoader获取资源

最近在写Servlet的时候,看到之前的代码里都是这样写的: InputStream is = xxx.class.getResourceAsStream(filePath); 但是我用另一种写法: ClassLoader.getSystemResourceAsStream(filePa...

JerryYux ⋅ 2014/08/30 ⋅ 0

eclipse下java动态编译时com.sun.tools.javac.Main类加载问题的解决

java.lang.NoClassDefFoundError: com/sun/tools/javac/Main 最近在使用java的动态编译的时候出现的问题,主要是由于在使用类com.sun.tool.javac.Main时,总是出现NoClassDefFoundError的错误,...

Jonee_Leo ⋅ 2012/06/16 ⋅ 0

理解 Java ClassLoader 机制

再次阅读这篇文章时,有了更深的体会,特转载之。 理解Java ClassLoader机制 当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构: bootstrap classloader | exte...

鉴客 ⋅ 2011/07/28 ⋅ 5

Spring源码学习之:ClassLoader学习(3)

ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回 这个类的class对象。 1.1 几个相关概念ClassLoader负责载入系统的所有Res...

无信不立 ⋅ 2016/11/07 ⋅ 0

ClassLoader&Class使用

ClassLoader一个经常出现又让很多人望而却步的词,本文将试图以最浅显易懂的方式来讲解 ClassLoader,希望能对不了解该机制的朋友起到一点点作用。 要深入了解ClassLoader,首先就要知道Cla...

ALibera ⋅ 2014/03/31 ⋅ 0

ClassLoader加载Class的过程 解析

ClassLoader即类加载器,负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象,当 JVM 启动时,会形成由三个类加载器组成的初始类加载器...

phacks ⋅ 2015/08/19 ⋅ 0

classloader总结

classloader是什么 我的理解classloader就是加载我们的类到内存的类,他主要就是寻找资源,即找到在他能搜索到的路径中,有没有我们的类。有的话就加载到内存。 系统的classloader 系统的cla...

xpbob ⋅ 2016/01/17 ⋅ 0

ClassLoader 详解及用途(写的不错)

ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。 1.1 几个相关概念ClassLoader负责载入系统的所有Res...

yuanhotel ⋅ 2015/09/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 39分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 46分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 53分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 54分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 58分钟前 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 今天 ⋅ 0

建造模式

《JAVA与模式》之建造模式

Cobbage ⋅ 今天 ⋅ 0

WePY框架开发的小程序如何在微信web开发者工具中运行起来

一、首先需要安装node.js,安装步骤如下: 首先下载安装包 https://nodejs.org/en/download/ 点击下载相应的zip版本 然后将文件夹解压到任意目录 比如我这里解压到了:C:\Program Files\node...

Helios51 ⋅ 今天 ⋅ 0

使用EnumSet 代替位域(32)

1、位域(Bit field):使用or 运算将几个常量合并到一个集合中 位操作,可以有效地执行 AND 、OR 这样的位操作 但是 位域比int 常量枚举缺点更多 2、java.util 包里面的EnumSet 类是有效的替...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部