读书人

《java深度历险》学习札记-深入类别载

发布时间: 2012-12-25 16:18:29 作者: rapoo

《java深度历险》学习笔记--深入类别载入器

1、什么是程序的动态性?
程序的动态性是指程序的class文件可以动态加载,这样做可以增加程序的弹性,节省内容,但是要以牺牲加载时间为代价,最重要的是它可以使程序在无需重启进行重新编译的情况下,更新程序功能。

?

2、程序动态性带来的好处

有了性,我的用程式就可以在不用全重新的情下更新系
,或者在不用停止主程式作的情下(尤其是您的系必24 小,一
停止就造成巨大失),除去系中原有的bug,或者是增加原本不具的
新功能。

?

3、java在动态性上和其他语言有什么不同?
c与c++本身不具有动态,它们的动态性需要借助操作系统提供的相关接口来实现,这就意味着程序要编写与本身业务逻辑无关的实现动态性的代码,这对于程序的维护不利;而java则是天生

具有动态性的语言,只是作为java程序员很少意识到动态性的存在,但是在java程序员想控制程序的动态性时,了解java语言动态性的内部实现机理是很有必要的。

?

4、java的程序动态性内部实现机理
Java 的朋友一定都知道,Java 是一天生就具有能力的技
。Java 把每的宣告、介面的宣告,在器理之後,全部成一
小的行位(, .class),一旦我指定一具有public static void
main(String args[])方法的作起始作之後,Java 器找
出所有在行期需要的行位,他入之中,彼此互相交互
作。管本上是一堆,但是在之中,成了一”上”一
的Java 用程式。所以,格的,每Java 器,都
是一立的函式,只不它的副名不是 .dll 或 .so,而是 .class
了。因特性,所以我可以在不重新其他Java 程式的情下,
只修改有的行位,放入案系之中,等到下次Java 器重
新,上的Java 用程式就因入了新修改的 .class ,
自己的功能也做了更新。是一最基本的性功能。

?

?5、入器的功用

就是把的硬碟(.class ),一份
放到之中,做一些初始化的工作,”活起”,其他人就能
使用它的功能。

?

6、为什么要掌握程序的动态性?
接下眼尖的朋友就了:「慢著,前面新的必要等到”下次
Java 器重新”才重新入,可是有些Web Server 或EJB
Container 本身就是用Java 所撰,他也是在Java 器上面行,那
,他如何在Java 器不重新的情下具有Hot Deployment 的
功能? 好吧!就算可以做到取新版本的功能好了,在不Java 器的
情下,所用的法放,那肯定充了同一
的新版本,如果Hot Deployment 的次太多,不爆掉?」。
是一非常好的,也是本章之所以存在的理由。

--本质上是通过类别载入器实现的,通过增加程序的弹性,来实现无需重启就进行功能的更新。

?

7、什么是类别载入器,它的主要作用是什么?
类别载入器也是jre的重要组成部分,他的主要作用是将硬盘中的.class文件拷贝一份到内存中,使之运行。

?

8、类别载入器的运行机理
当用户在执行 java **.java命令时,java.exe会利用几个基本原则找到jre,然后把**.java对应的.class文件放到jre上执行,这样java.exe的作用就结束了,但是在这个过程中类别载入器

还实现了以下两个功能,一将对应jre下的基础类别函数库rt.jar载入内存中这叫预先载入,二将**.java对应的.class文件及相关的.class文件载入到内存中,这叫按需载入。

像基函式的入方法我叫做先入(pre-loading),是
因基函式的大多是Java 程式行所必的,所以
了不要老是做浪的I/O 作(取案系,然後入之
中),先入些Java 用程式在行速度稍微快一些。相
,我自己所撰的之入方式,叫做依需求入(load-on-demand),
也就是Java 程式真正用到的候,才真的把案系之中入
。,只有宣告(如: B )而已,是不促使入器
我入的,只有化指令(new XXX())才入器我入
。的,就性上和速度上的考量,如此的所的(性和省
)超外入的花(只有第一次用到),因此依需求入的
是明智的。

?

9、按需载入时类别载入器的载入原则
类别载入器的载入原则是只有实例化了的类的.class文件才会被载入,程序员可以利用这个原理来节省内存的开销。

?

10、按需载入的优缺点
按需载入的优点是可以节省内存空间的使用,缺点是需要更多的加载时间,但是这个加载时间也只有第一次加入时,因为载入后保留到内存中,即可随时使用无需重复载入,直到java虚拟机

关闭。它的本质是以时间换空间。

?

?11、式的(implicit)方法我已了,也就是程式用到new
Java 字,入器依需求入您所需要的,方式使用了
式的(implicit)方法,者在前面提到『一般使用Java 程式言用程
式的工程眼中,很少有能察Java 因具了性之後所的
和特性,甚至根本不曾利用Java 先天就具有的特性。不是我的
,而是因的本被巧妙地藏起,使得使用Java 的程式
在不知不中用到了性而不自知』就是因如此。但是,式的(implicit)
方法仍有其限制,法成更多的性,遇到情,我就必用式的
(explicit)方法完成。式的方法,又分成方式,一是藉由java.lang.Class 的forName()
方法,另一是藉由java.lang.ClassLoader 的loadClass()方法。

?

12、「那,有有更好的方法,可以在不
修改主程式的情下增加主程式的功能?」有的,使用式的方法所成的
性,可以增加程式的性,成我不希望修改主程式的需求

?

import java.net.* ;20public class Office{public static void main(String args[]) throws Exception{URL u = new URL("file:/d:/my/lib/") ;URLClassLoader ucl = new URLClassLoader(new URL[]{ u }) ;Class c = ucl.loadClass(args[0]) ;Assembly asm = (Assembly) c.newInstance() ;asm.start() ;}}

?

在例中,我自己生 java.net.URLClassLoader 的我
入我所需要的。但是入前,我必告URLClassLoader 去哪
地方找我所指定的才行,所以我必它一URL 所成的
列,代表我希望它去搜的所有位置。URL 可以指向路上的任何位置,
也可以指向我的案系(包含JAR )。在上述例中,我希望
URLClassLoader 到d:\my\lib\目下去找我需要的,所以指定
的URL ”file:/d:/my/lib/”。其,如果我求的位置是主要(有public
static void main(String arga[])方法的那)的相目,我可以在URL
的地方只”file:lib/”,代表相於目前的目。您可以,同一,被不同的 URLClassLoader 分入,而且分初始化一次。也就是,在一器之中,相同的被入了次。

?

19、出中我可以得知,Office.class 由AppClassLoader(又做System
Loader,系入器)所入,URL.class URLClassLoader.class 由Bootstrap
Loader 所入(注意:出null 非代表不是由入器所入。在Java 之
中,所有的都必由入器入才行,只不Bootstrap Loader 非
由Java 所撰而成,而是由C++作而成,因此以Java 的看,上
有Bootstrap Loader 的)。而Word.class 分由不同的
URLClassLoader 入。至於Assembly.class , 本身是由
AppClassLoader 入,但是由於多型(Polymorphism)的,所指向的
(Word.class)由特定的入器所入,致列印在幕上的容是其所考
的之入器。Interface 型本身法直接使用new 生
,所以在行getClassLoader()的候,叫用的一定是所考的
的getClassLoader(),要知道Interface 本身由哪入器入,您必
使用底下程式:
Assembly.class.getClassLoader()

?

20、我在命令列入 java xxx.class 的候,java.exe 根我之前所提
的找到了JRE(Java Runtime Environment),接著找到位在JRE 之中的
jvm.dll(真正的Java 器),最後入函式,Java
器。作的介回第一章。
器一,先做一些初始化的作,比方抓取系等。一旦
初始化作完成之後,就生第一入器,即所的Bootstrap
Loader,Bootstrap Loader 是由C++所撰而成(所以前面我,以Java
的看,上不存在Bootstrap Loader 的,所以在Java 程
式印出其容的候,我看到的出null),Bootstrap
Loader 所做的初始工作中,除了也做一些基本的初始化作之外,最重要的就
是入定在sun.misc 命名空底下的Launcher.java 之中的
ExtClassLoader( 因是inner class , 所以之後成
Launcher$ExtClassLoader.class),定其Parent null,代表其父入器
Bootstrap Loader。然後Bootstrap Loader 再要求入定於sun.misc 命
名空底下的Launcher.java 之中的AppClassLoader(因是inner class,
所以之後成Launcher$AppClassLoader.class),定其Parent
之前生的ExtClassLoader 。要大家注意的是,
Launcher$ExtClassLoader.class Launcher$AppClassLoader.class 都是
由Bootstrap Loader 所入,所以Parent 和由哪入器入有。。最後
一步,是由AppClassLoader 入我在命令列之中所入的
xxx.class(注意:上xxx.class 很可能由ExtClassLoader 或Bootstrap
Loader 入,考底下「委派模型」一),然後始一Java 用程式的
生命期

,入器由入(句有,入器也要由入器
入,是因除了Bootstrap Loader 之外,其的入器皆是由Java 撰
而成),和它的Parent 是有,Parent 的存在只是了某些特殊目的,
目的我在稍後作解

在此要大家注意的是,AppClassLoader 和ExtClassLoader 都是
URLClassLoader 的子。由於它都是URLClassLoader 的子,所以它
也有URL 作搜的考,由原始中我可以得知,
AppClassLoader 所考的URL 是系java.class.path 取出的字串所
定,而java.class.path 是由我在行java.exe ,利用 cp 或
-classpath 或CLASSPATH 境所定。

?

21、出果,我可以看出,在情下,AppClassLoader 的搜路
”.”(目前所在目),如果使用-classpath (-cp 等效),就可以改
AppClassLoader 的搜路,如果有指定-classpath ,就搜境
CLASSPATH。如果同有CLASSPATH 的境定-classpath ,
以-classpath 的容主,CLASSPATH 的境定-classpath 者
的容不有加成的效果。至於 ExtClassLoader 也有相同的情形,不其搜路是考系
java.ext.dirs。出果告我,系java.ext.dirs 的容,指向java.exe 所的
JRE 所在位置下的\lib\ext 子目

最後一入器是 Bootstrap Loader,我可以由查由系
sun.boot.class.path 得知Bootstrap Loader 用搜的路。

三入器的搜路所考的系的名字中,其透漏了
一息。回看到java.class.path sun.boot.class.path,也就是,
AppClassLoader Bootstrap Loader 搜它所指定的位置(或JAR ),
如果找不到就找不到了,AppClassLoader Bootstrap Loader 不式地
搜些位置下的其他路或其他有被指定的JAR 。反
ExtClassLoader,所考的系是java.ext.dirs,意思是,他搜底
下的所有JAR 以及classes 目,作其搜路(所以您上面我在
的候,如果加入 -Dsun.boot.class.path=c:\winnt ,程式的起
始速度慢了些,是因c:\winnt 目下的案很多,必花外的
列JAR )。

在命令列下,使用 classpath / -cp / 境CLASSPATH 更
改AppClassLoader 的搜路, 或者用 Djava.ext.dirs 改
ExtClassLoader 的搜目, 者都是有意的。可是
用Dsun.boot.class.path 改Bootstrap Loader 的搜路是效。是
因AppClassLoader ExtClassLoader 都是各自考系的
容而建立,您在命令列下更系之後, AppClassLoader
ExtClassLoader 在建立的候考系,因而改了它搜
的路;而系sun.boot.class.path 是Bootstrap
Loader 的搜路相同,就算您更改系,Bootstrap Loader 完全

?

更重要的是,AppClassLoader ExtClassLoader 在整器之中只
存有一份,一旦建立了,其部所考的搜路不再改,也就是,即
使我在程式利用System.setProperty()改系的容,仍然法更
AppClassLoader ExtClassLoader 的搜路。因此,行期更
改搜路的定是不可能的事情。如果因特殊需求,有些的所在路
非在一始就能定,那除了生新的入器助我入所需的
之外,有其他方法了。

?

22、所的委派模型,用
的,就是「入器有入的需求,先示其Parent 使用
其搜路忙入,如果 Parent 找不到,那才由自己依照自己的搜路

出我可以看出, AppClassLoader 要入test.class ,先其
Parent,也就是ExtClassLoader 入,而ExtClassLoader 又求其Parent,
即Bootstrap Loader 入test.class。由於<JRE 所在目>\classes 目

Bootstrap Loader 的搜路之一, 所以Bootstrap Loader 找到了
test.class,因此它入。接著在test.class 之有入testlib.class 的需求,
由於test.class 是由Bootstrap Loader 所入,所以testlib.class 定是由
Bootstrap Loader 根其搜路找,因testlib.class 也位於Bootstrap
Loader 可以找到的路下,所以也被入了。

出我可以看出, AppClassLoader 要入test.class ,先其
Parent,也就是ExtClassLoader 入,而ExtClassLoader 又求其Parent,
即Bootstrap Loader 入test.class。由於<JRE 所在目>\classes 目
Bootstrap Loader 的搜路之一, 所以Bootstrap Loader 找到了
test.class,因此它入。接著在test.class 之有入testlib.class 的需求,
由於test.class 是由Bootstrap Loader 所入,所以testlib.class 定是由
Bootstrap Loader 根其搜路找,但是因Bootstrap Loader 根本
找不到testlib.class(被我除了),而Bootstrap Loader 又有Parent,所
以法入testlib.clss。

出我可以看出, AppClassLoader 要入test.class ,先其
Parent,也就是ExtClassLoader 入,而ExtClassLoader 又求其Parent,
即Bootstrap Loader 入test.class。但是Bootstrap Loader 法在其搜
路下找到test.class(被我掉了),所以ExtClassLoader 只得自己搜。
因此ExtClassLoader在其搜路<JRE所在目>\lib\ext\classes底下找到
test.class,因此它入。接著在test.class 之有入testlib.class 的需求,
由於test.class 是由ExtClassLoader 所入,所以testlib.class 定是由
ExtClassLoader 根其搜路找, 但是因ExtClassLoader 有
Parent,所以要先由Bootstrap Loader 先忙找,testlib.class 位於
Bootstrap Loader 可以找到的路下,所以被Bootstrap Loader 入了。

?

「入器可以看到Parent
所入的所有,但是反非除此

?

23、其不
只是JDBC,在Java 域中只要分成API(Application Programming
Interface,公制定,成核心函式(由Bootstrap Loader 入)或
充函式(由ExtClassLoader 入))SPI(Service Provide Interface,由
特定商撰,成充函式(由ExtClassLoader 入)或用程式(由
AppClassLoader 入)的一部分)的函式,都遇到此,比方JDBC 或
JNDI 就是最好的例子。解的方法是透Context Class Loader,不
本章不此行。

?

24、整程序是子的: 一始的候,我在命令列入java office Word,所
以AppClassLoader 必入Office.class , 由於其
Parent(ExtClassLoader)Parent 的Parent(Bootstrap Loader)都法在其
搜路找到Office.class , 所以最後是由AppClassLoader 入
Office.class。我在Office.class 之中,需要建立URL URLClassLoader
的,使用的入器是所在的本身的入器,也就
是利用ClassLoader.getCallerClassLoader() 取得的入器( 注意,
ClassLoader.getCallerClassLoader()是一private 的方法,所以我法
自行叫用,是new 算子本身函的呼叫制中自行使用的)。接下,
AppClassLoader 仍然去求其Parent(ExtClassLoader)Parent 的
Parent(Bootstrap Loader)入,其中,Bootstrap Loader 在<JRE 所在目
>\lib\rj.jar 之中找到URL.class URLClassLoader.class,所以理所然由
Bootstrap Loader 入。最後,我求URLClassLoader 到相路下
的lib\ 子目入Word.class , 入Word.class 之前, 必先入
Assembly.class,所以URLClassLoader 求其Parent(AppClassLoader)、
Parent 的Parent(ExtClassLoader)Parent 的Parent 的Parent(Bootstrap
Loader)入,所以最後由AppClassLoader 入Assembly.class,而由
URLClassLoader 入Word.class。然後因Assembly.class 的(asm
asm1)考到的事Word.class 的(c c1),所以最後印出果是
URLClassLoader 入的,但是如果我直接用Assembly.getClassLoader(),
就示出是AppClassLoader 入的。

?

25、上面的和明,我了解了入器和其入制是一非常
的系,那何要的系呢? 除了可以到性之外,其
最重要的原因莫於安全性。我以下面明:
ExtClassLoader
Bootstrp Loader
Parent
AppClassLoader
Parent
URLClassLoader
Parent
URLClassLoader
Parent
自於www.sun.com 自於www.xxx.com
明了件事情,第一,假我利用 URLClassLoader 到路上的任
何地方下了其他的,URLClassLoader 都不可能下AppClassLoader、
ExtClassLoader、或者Bootstrap Loader 可以找到的同名(指全名,套件
名+名),因此,蓄意破者根本有植入有的程式於我的
之中(除非蓄意破者能入您的,置掉您的,但是
已不是Java 所涉及的安全了,而是作系本身的安全)。第二,
入器法看到其他相同之入器所入的,如上所示,
中索框起的部分意指www.sun.com 下程式的入器所能看
到的。告我www.sun.com 入的,法看到www.xxx.com
入的,除了意味著不同的入器可以入完全相同的之外,也
排除了用或意使用人程式的。

读书人网 >编程

热点推荐