原文转自:
http://yueyemaitian.iteye.com/blog/1185339
一、ClassLoader
负责装载class文件;这个文件来源可能是压缩包、网络、运行时编译出的或者自动生成的class文件,jvm spec没有规定必须从什么地方加载。
jvm中默认提供了三种系统类加载器:
1)、启动类加载器Bootstrap ClassLoader,负责加载%JAVA_HOME%\jre\lib目录下的包,
2)、扩展类加载器Ext ClassLoader,负责加载%JAVA_HOME%\jre\lib\ext目录下的包,或者在java.ext.dirs系统变量锁指定的路径中的所有类库
3)、应用程序类加载器App ClassLoader,负责加载用户classpath中的包
用户也可以自定义自己的classloader,来根据自己的需求装载类文件
ClassLoader是双亲委派模型,除了Bootstrap ClassLoader外每个classloader都有自己的父加载器,每个加载器在加载某个类之前,先委托父加载器在其相关的目录加载,如果加载不到,则自己加载。
二、ClassLoader扩展的实例
1、Tomcat的类加载体系结构:
为了解决部署的web app与tomcat自身共享一份运行时代码实例、各个web app共享一份运行时代码实例、tomcat自身和各个web app私有的一份运行时代码实例,自定义了几个classloader,用来解决运行时类库的共享和隔离问题
其中Common CL是用来加载tomcat和web app共用的类库的;Catalina CL是加载Tomcat专用的类库的;Shared ClassLoader是加载web app共用的;WebApp CL用来加载应用专用的类库的web app下WEB-INF\lib下的包的;Jasper CL用来加载jsp页面,一个页面一个classloader,用来实现热替换的。
在Tomcat v5.5的时候,%CATALINA_HOME%下的common、server、shared分别由Common CL、Catalina CL、Shared CL分别加载;在Tomcat v6,则通过%CATALINA_HOME%/conf/catalina.properties下的common.loader、 server.loader、shared.loader分别设置需要相关classloader加载的jar包
2、OSGi的类加载体系结构
OSGi的 Bundle之间相互引用,需要Export、Import的,一个Bundle Export出去的类才能被外部的Bundle Import到,外部的包对Import的类的加载也需要Export出该类的Bundle的ClassLoader来完成。每个Bundle一个 ClassLoader。
3、如果做一个大型CS系统,jar包太多,比如说大于1G甚至更多;然后eclipse里把这些包作为project的library,但是启动client的时候,发现出错了
- Exception occurred executing command line.
- Cannot run program "D:\Program Files\Java\jdk1.6.0_18\bin\javaw.exe" (in directory "E:\workspace\myproject" ): CreateProcess error= 87 , ²ÎÊý²»
搜索发现是因为classpath太长了导致的,启动不了jvm,当然也可以通过虚拟盘 , 缩短classpath的方式解决该问题,而且是一种不错的办法,但是有没有其他的办法呢?classloader,对,既然classloader把一 部分装载类的权利给了我们,我们就要充分利用,我们在启动的时候加上我们自己的classloader,设置上我们自己的classpath,这个 path只填写目录名,我们在classloader中扫描目录名,然后把jar文件一个个的放入到classpath中就解决问题了
此处,设置cloassloader的命令行是哪个?设置classpath的命令行是哪个?
4、系统里边很多 jar包,当系统需要加载某个类的时候,需要扫描所有的jar包,找到这个class在不在这个jar文件里头。如果系统里jar包很多,比如说有1g甚 至更多,此时这样扫描效率就很低。如果有一种方式知道我某个类就在那个某个包里,一步就定位到了那个包,然后加载,效率岂不是很高?就此问题,我们可以先 在应用部署的时候,或者服务器启动的时候,扫描一下所有的jar包,然后在一个文件里写入package路径对应哪个jar文件,比如 com.xyz.sis.app = abc.jar。然后自定义一个ClassLoader,classloader在加载的时候缓存上边这个映射结果,直接根据要加载的类的全限定名来定位 到相应的jar包,然后加载相关的类,速度不是很快?
jvm的app classloader有没有在扫描完一次所有的jar后,缓存下哪个package对应到那个包,或者是哪个类对应到哪个包?缓存的成本。