The Extension Mechanism

今天决定研究一下JAR中的MAINFEST的作用。于是,看到这个文档:
http://docs.oracle.com/javase/tutorial/ext/basics/index.html
真心不错。仔细研读,写一篇总结。

Java中应用扩展有两种途径:
第一种:install extension。就是把jar包放到JRE\lib\ext目录下。这个影响是全局性的,所有被这个JRE启动的Java虚拟机进程共享这个目录。没有这么做过。jdk6增加了一种更加全局的支持:可以把jar放到一个指定的文件夹,这样就能在本地机器上所有的JRE之间共享jar包。具体设置如下:
Solaris™ Operating System: /usr/jdk/packages/lib/ext
Linux: /usr/java/packages/lib/ext
Microsoft Windows: %SystemRoot%\Sun\Java\lib\ext

第二种:download extension。就是通过MANIFEST.MF文件来指定应用需要的扩展。这里又分为两种方式:
by a Class-Path header
by an Extension-List header
每个MANIFEST文件中只能出现二者之一。有什么不同呢?第一种,只在应用的生命周期下载用到的jar;第二种会把jar放到JRE\lib\ext里,有点install extension的味道。

看完了这些资料总结成一句话:MANIFEST.MF就是为了不把所有的被依赖的jar包都放到CLASSPATH里。当然还有其他的因素,比如便于类的加载为类加载器控制,形成层次化。举个例子,A.jar中的MANIFEST.MF文件的class-path中有对B.jar的引用。如果A.jar的类是被ClassLoader1所加载,那么当需要加载B.jar中的类时,也会用ClassLoader1加载。当然,这里指的是A中的类对B中的类的直接引用,而且B还没有被ClassLoader1的parent所加载。

具体一些:如果位于A.jar中的A.class时应用程序入口,且引用了B.jar中的B.class。其中,A.jar中的MANIFEEST.MF中的Class-Path有对B.jar的引用。
启动程序java -cp A.jar A
sun.misc.Launcher$AppClassLoader的实例试图加载A.class,它把这个请求委托给了它的父加载器sun.misc.Launcher$ExtClassLoader,而ExtClassloader又把请求委托给了BootStrapClassLoader。这就达到了委托链的尽头,BootStrapClassLoader只能自己试图加载A.class,它去哪里找呢?BootStrapClassLoader去rt.jar等JRE的运行时的jar中去找。这显然是找不到的。所以它告诉它的委托人(就是sun.misc.Launcher$ExtClassLoader):我已经尽力了,没找到啊!接下来sun.misc.Launcher$ExtClassLoader只好自己动手去找,它去哪里找呢?前面提过JRE\lib\ext。这个还是找不到,于是它就只好告诉委托人(sun.misc.Launcher$AppClassLoade):我找不着!接下来,sun.misc.Launcher$AppClassLoade只好自己找,怎么着?属性java.class.path,它的默认值是.就是当前目录。这个值可以通过-cp 或者-classpath或者CLASSPATH环境变量来修改。sun.misc.Launcher$AppClassLoade回去java.class.path中的每个class,每个jar去遍历寻找。如果是class直接看是不是A.class,如果是jar就进入jar中寻找。如果还没找到,就去jar的MANIFEST.MF中Class-Path中列的jar中继续寻找。最终,在A.jar的MANIFEST.MF中定位到了B.jar,在B.jar中找到了B.class。分析到这里,我们知道了,MANIFEST.MF中的Class-Path中指定的jar起到了扩展当前ClassLoader的class path的作用。

这里举的是很简单的例子,如果在应用服务器中会更复杂一些。有时间我会尝试剖析一下JBoss、Weblogic、Websphere的类加载机制。


接下来还想搞清classloader是如何解析MANIFEST的,这个需要另开一篇。

你可能感兴趣的:(ext)