您的位置:首页 > 编程语言 > Java开发

传智播客Java web之 Servlet中的类装载器详解

2009-10-23 20:35 281 查看
随着视频实践完第一个Servlet后,对Servlet有了一些感性的认识。接着视频讲解了一个比较深入和很少碰到的知识点。虽然很少接触,但是理解该知识点后,对servlet乃至java的运行原理会有进一步的认识。这个知识点就是类装载器,张老师对这个问题讲解的很透彻,也演示了很多通俗易懂的例子。
Java虚拟机使用每一个类的第一件事情就是将该类的字节码装载进来,装载类字节码的功能是由类装载器完成的,类装载器负责根据一个类的名称来定位和生成类的字节码数据后返回给Java虚拟机。类装载器本身也是一个Java类, Java虚拟机也允许开发人员编写自己的类装载器,以便通过其他各种特殊方式来产生类字节码。不管类装载器采用什么方式,只要能够在内存中制造出给Java虚拟机调用类字节码即可,所以,把类装载器描述为类字节码的制造器更容易让人理解。当一个类被加载后,Java虚拟机将其编译为可执行代码存储在内存中,并将索引信息存储进一个HashTable 中,其索引关键字为与之相对应的类名。 Java程序中的类本身也是一种事物,它也可以用一个Java类描述,这个特殊的类名就叫Class。类装载器装载某个类的字节码的过程实际上就是在创建Class类的一个实例对象,这个Class类的实例对象封装的内容正好是当前加载的类的字节码数据。要想在程序中获得代表某个类的字节码数据的Class实例对象,可以采用下面三种方式:
1.类名.class,例如,System.class
2.对象.getClass(),例如,new Date().getClass()
3.Class.forName("类名"),例如,Class.forName("java.util.Date");
Java类库中提供了一个java.lang.ClassLoader来作为类装载器的基类,Java虚拟机和程序都调用ClassLoader类的loadClass方法来加载类,ClassLoader是一个抽象类,真正的类装载器必须是ClassLoader的子类。Class类中定义了一个getClassLoader方法,用于返回它所描述的类的类加载器对象,这个返回对象的类型就是ClassLoader。
了解了类装载器是什么以及它的作用。视频接着讲解了类装载器的基本策略,在java中,一个类装载器本身也是一个Java类,所以,类装载器自身也需要被另外一个类装载器装载。Java虚拟机中内嵌了一个称为Bootstrap的类装载器,它属于Java虚拟机的内核,不用类装载器装载。Bootstrap类装载器负责加载Java核心包中的类(即rt.jar文件中的类),这些类的Class.getClassLoader方法返回值为null,即表示是Bootstrap类装载器。ExtClassLoader类装载器负责加载存放在<JAVA_HOME>/jre/lib/ext目录下的jar包中的类,AppClassLoader负责加载应用程序的启动执行类。下面一个例子演示了各个类装载器负责加载哪些类:
public class ClassLoaderTest
{
public static void main(String [] args)
{
//测试rt.jar中的类
ClassLoader cl = System.class.getClassLoader();
System.out.println(cl==null?"null":cl.getClass().getName());
cl = javax.swing.Box.class.getClassLoader();
System.out.println(cl==null?"null":cl.getClass().getName());
//测试<jre_home>/lib/ext中的jar中的类,就是用该目录中的任何一个jar包中的一个类
cl = com.microsoft.util.UtilByteArray.class.getClassLoader();
System.out.println(cl==null?"null":cl.getClass().getName());
//测试当前运行类
cl = Test2.class.getClassLoader();
System.out.println(cl==null?"null":cl.getClass().getName());
}
}
视频中对类装载器的委托模式讲解很透彻,下面就是有关委托模式的知识点:
1.一个Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象,如果没有指定的话,则以ClassLoader.getSystemClassLoader()方法返回的系统类装载器作为其父级类装载器对象。
2.系统类装载器通常被设置为启动应用程序的AppClassLoader,可以通过java.system.class.loader系统属性来将系统类装载器设置为其他类装载器。ExtClassLoader是AppClassLoader父级类装载器,ExtClassLoader没有父级类装载器。
每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载。
3.当要加载一个类时,ClassLoader的loadClass方法先查找这个类是否已被加载,如果没有加载则委托其父级类装载器去加载这个类,如果父级的类装载器无法装载这个类,子级类装载器才调用自己内部的findClass方法去进行真正的加载。委托过程会一直追溯到BootStrap类装载器,如果委托过程中的所有类装载器都不能完成类的装载,最终就会报告ClassNotFoundException异常。
4.一个类装载器只能创建某个类的一份字节码数据,即只能为某个类创建一个与之对应的Class实例对象。在一个Java虚拟机中可以存在多个类加载器,每个类加载器都拥有自己的名称空间,对于同一个类,每个类加载器都可以创建出它的一个Class实例对象。
5.采用委托模式避免了一个Java虚拟机中的多个类装载器为同一个类创建多份字节码数据的情况。只要开发人员自定义的类装载器不覆盖ClassLoader的loadClass方法,而是覆盖其findClass方法,这样就可以继续采用委托模式。
有了类装载器的知识,就应该实际了解Tomcat中的类装载器。总共有6类装载器,详细信息在Tomcat官网:http://tomcat.apache.org/tomcat-5.5-doc/class-loader-howto.html 。它们负责装载的类分别是:
1.Bootstrap为Java虚拟机内嵌的类装载器与ExtClassLoader的总称,负责加载Java核心包中的类和存放在<JAVA_HOME>/jre/lib/ext目录下的类。
2.System即系统类装载器,通常情况下就是AppClassLoader,负责加载CLASSPATH环境变量设置的目录中的类。Tomcat不会继承操作系统上原来设置好的CLASSPATH环境变量的内容,而是将CLASSPATH环境变量重新设置为仅包含如下两个jar包:
<CATALINA_HOME>/bin/bootstrap.jar
<JAVA_HOME>/lib/tools.jar
3.Common类装载器负责从<CATALINA_HOME>/common/classes中的.class类文件和<CATALINA_HOME>/common/lib中的jar包加载类。
4.Catalina类装载器负责从<CATALINA_HOME>/server/classes中的.class类文件和<CATALINA_HOME>/server/lib中的jar包加载类。
5.Shared类装载器负责从<CATALINA_HOME>/share/classes中的.class类文件和<CATALINA_HOME>/share/lib中的jar包加载类。
6.WebappX类装载器负责从当前Web应用程序的/WEB-INF/classes中的.class类文件和/WEB-INF/lib中的jar包加载类。
在最新的Tomcat6中,类装载器有了新的变化,可以参考:http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html。所以要了解最新的技术规范,查官方文档是最有效,也最准确的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: