Java 类装载器详解

[align=center]Java类装载器详解[/align]
一:标准JavaSE 类装载器
1.标准JavaSE 类装载器概述
本质上来说,类装载器是以某种方式,读取Java类的class文件到JVM中,并将class文件中的信息写入到内存中的一种机制。Java语言中的类装载器可以分为两种:一种是用Java语言编写的(Java程序员只需要关注这种类型的类装载器即可);一种不是用Java语言编写的,我们称之为启动类装载器,它是Java虚拟机实现的一部分。
2.启动类装载器
顾名思义,启动类装载器是用于装载JVM启动时需要的Java类。实际上,启动类装载器负责装载所有核心的Java类(例如 java.lang.*和 java.io.*)。启动类装载器以某种特定的方式从本地磁盘(Java虚拟机安装目录)中装载JVM运行所需的Java类。例如如果JVM是用C或者C++编写的,那么JVM的实现者可以调用C或者C++的API来装载Java class文件到JVM中。有些人知道了启动类装载器装载了核心的Java类,他们可能还想知道,启动类状态器具体在哪里找到这些类。JAR文件的查找方法因厂商的不同而变化。例如Sun的Java SE 5 JVM在<JDK>/jre/lib目录下查找JAR文件,尤其在<JDK>/jre/lib/rt.jar目录下查找启动类。对于Sun的JVM,可以使用 -Xbootclasspath 为JVM查找启动类的位置,一般而言,我们不需要这么做。
(启动类装载器在一个JVM实现中,只有一个。也有翻译成引导类装载器,原始类装载器的,但我觉得启动类装载器最为精确)
3.扩展类装载器
Java 1.2 引入了标准扩展机制。通常情况下,当我们想让JVM在某个特定的位置查找类文件时,我们会更改CLASSPATH环境变量,将类文件加入到CLASSPATH环境变量中。(或者使用 -classpath 选项)。Sun引入了标准扩展机制作为一个可选的方法,可以将JAR文件放入到标准扩展目录,JVM将自动找到他们。
一般情况下,扩展类装载器是用Java语言编写的。标准扩展目录也会随着JVM厂商的不同而不同,Sun的JVM的标准扩展目录为<JDK>/jre/lib/ext。
4.系统类装载器
系统类装载器是Java 1.2引入的系统默认Java实现,当然,它是用Java编写的。系统类装载器在目录和CLASSPATH环境变量指定的JAR文件中查找自己的类,或者通过-classpath命令行选项传递的类。系统类装载器也用于装载应用程序的entry point类(即含有main()方法的类),对于那些其他任何没有上述的两类类装载器装载的类,都默认使用系统类装载器。
(系统类装载器有时被称为应用程序类装载器,虽然更为贴切,不过系统类装载器是Sun的约定)
二:委派模型

如前所述,Java SE用于3种不同的类装载器。他们之间的关系可以用父子关系形容。启动类装载器是爷爷,系统类装载器是孙子,优先级最低。JDK1.2以后的JVM版本都会使用委派模型。当JVM受到装载类的请求时,只有在父类装载器未能装载该类的情况下,原始类(子类)才会尝试装载该类。举个例子来说,你定义了一个类名为A的类。当你请求装载该类时,系统类装载器会受到请求(为什么是系统类装载器会先收到请求?),他首先想到的不是自己去装载这个类,而是会想,难不成他在扩展类装载器那?于是乎他就找到扩展类装载器,问他类A在你那吗?扩展类装载器收到请求后第一件事情也不是做事,而是在想,难不成他在启动类装载器那?于是乎,他又找到了启动类装载器,问他了,喂看看类A在你那不?当然了,启动类装载器在接到请求后,第一件想到的事情也不是自己去装载类A啊,他也想问他老子啊,可他一看,他前面没人了啊 :D 。于是乎,没办法,他就到自己的装载域中找找看有没有类A。找了半天,他没发现类A,他就告诉扩展类装载器,跟他说,我这没有啊 ,你自己找找看吧,扩展类装载器就去自己的装载域中找了,结果没发现,于是,他也只能不好意思的跟系统类装载器说,我这也没有啊 ,还是你自己来吧。于是,系统类装载器就自己去找了,他当然能找到啦,于是就把对象的引用返回了。(写了这么久的Java程序了,有没有弄清楚,JVM在什么时候装载一个类?)
三:Endorsed Standards Override 机制
Java 1.4引入了称为 Endorsed Standards Override 机制的概念,在Java SE1.5中也可以使用该机制。随着时间的推移,核心的Java SE发布已经包括越来越多的Java扩展(曾经认为是可选的)。其中一个很好的例子就是J2SE 1.4包含XML处理的Java API(JAXP)。既包括JAXP的API类,也包括其实现。实现类包含在rt.jar中,启动类装载器将装载它们。因此,如果程序员将更新版本的JAXP实现与该JDK一起放到CLASSPATH中,新的版本将不能使用。
四:Java 类装载器在安全模型中扮演的角色
在计算机的世界里,以说到安全问题,我们可就又回到了严肃而认真的问题上了。显然,类装载器体系位于Java安全模型的中心。(为什么?)是否还记得我们上述的三种类装载器,其中最重要的就是启动类装载器装载的类了,如果一个第三者的java.lang.String 插足到JVM中了,他成了你调用的String 类,结果他把你的硬盘给格了,你是否会崩溃?
1.委派模型
前述的委派模型通常被描述为一个安全特性。你看了之后是不是也觉得是那么回事呢?
启动类装载器装载了所有的JVM自带的核心Java API。任何装载核心的Java类的请求,都会在启动类装载器那获得它所保存的副本。
但是,委派模型并不是JVM规范的一部分,所以委派模型在安全方面是存在缺陷的。(乖乖,又想到一个问题,为什么不把他加入到JVM规范中呢?那样Java岂不是更安全?)
2.我们不是可以自定义类装载器吗?你要是不把请求委派给父类装载器,你怎么阻止别人装载java.lang.String呢?事实上任何用Java语言编写的类装载器,都不能装载核心的Java类。ClassLoader抽象类(所有类装载器必须继承的)禁止创建任何以java开始的类。你的类装载器还能装载核心的java类吗?不能吧?那还是让启动类装载器来干吧。
4.第二条所述的只是在装载类的时候,限制了错误的核心类被装载,那么在运行时,怎么保证JVM的安全呢?Sun的策略有两种,第一就是独立的类装载器命名空间。
JVM在运行时,会为每个类监视每个运行的类装载器,并为之分配一个唯一的命名空间。并且,当JVM在运行Java代码时,收到一个类发出装载另一个类的请求时,他会先找到装载发出请求的类的装载器,并用他来装载待装载的类。这样的话,不同的类装载器装载的类就会有不同的命名空间。同一个类装载器装载的类之间可以进行直接交换,不同的类装载器装载的类之间不可以进行直接交换,JVM会禁止这样的行为,除非你的程序显式的允许。大家都知道,在Java语言中,我们区分不同的类,是通过包名加类名(完全限定名),实际在JVM中,还会在你的类之前加上类装载器的命名空间。也就是说,两个不同的类装载器均装载了com.Test.java这个Java类,在JVM看来,会认为他们不是同一个类。这样的话,在运行状态下,恶意的代码就不能够破话善意的代码了。
5.Security Manager
如果真的想保证自定义类装载器不能破坏程序,可以在应用程序中完全阻止它。这可以通过Security Manager类完成。
使用Security Manager和它的策略文件,可以在应用程序中阻止(或者不阻止)大量的任务。例如,可以阻止应用程序打开和某个网络主机的socket连接,或者打开某个本地文件。此外,还可以阻止应用程序装载类装载器。
至于怎么使用Security Manager则又是另外一个话题了。
四:类装载器的其他行为
1.延迟加载
2.类缓存

五:为什么我们要学习类装载器
这个问题问的真是好,我说了那么多废话,只是让我们学习了之后去写属于我们自己的类装载器吗?当然不是,很少情况下,我们需要写。
那么,学习类装载器干什么?我们不知道他,还不是照样可以编程,照样做Java程序员,事实上,我也经常问自己这些问题 :) 。
由于本人Java的从业时间不长,知道的不多。
目前来看,主要有:
1.深入Java虚拟机的学习有帮助
2.我在学习Tomcat时,也有很多帮助。比如Tomcat中不同的Context。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值