Coder 爱翻译 How Tomcat Works 第八章 第一部分

Chapter 8: Loader

在前几章你有一个简单的加载器实现,它用来加载servlet类。本章讲解标准web应用加载器。一个serlvet容器需要一个定制的加载器,它不能简单地使用系统类加载器,因为它不能确定servlet正在运行情况。如果它打算加载所有的servlet和其它需要的类,servlet通过系统类加载器,然后一个servlet应该可以访问运行在JVM中CLASSPATH环境变量下的任何类和类库。这样就会出现安全问题。一个servlet只允许加载在WEB-INF/classes目录和它子目录下的类和部署在WEV-INF/ilb目录下的类。这就是为什么一个servlet容器需要有它自己的加载器。在servlet容器里的每一个web应用程序有自己的加载器。一个加载器应用某种规则来加载类。在Catalina里,一个加载器由org.apache.catalina.Loader接口代表。

另外一个Tomcat需要它自己的加载器的原因是:支持在一个在WEB-INF/classes和WEB-INF/lib下的类被改变时可以动态重新部署。在Tomcat中的类加载器的实现使用一个独立的线程来检查servlet和类文件的时间戳。要支持动态重新加载,一个类加载器必须实现org.apache.catalina.loader.Reloader接口。

本章第一部分简单回顾java中的类加载机制。接下来讲述所有加载器都必须实现的Loader接口。本章的应用程序也演示了Tomcat怎么使用它的加载器。

本章的两项扩展:repository 和resources。一个repository是类加载器将要搜索的地方。Resources参考一个类中的DirContext对象,DirContext对象的文档库(document base)指向context的文档库。

Java Class Loader

每次你创建一个java类的实例,类首先会被加载到内存。JVM使用一个类加载器来加载类。通常是类加载器搜索一个核心java类库和包含在CLASSPATH环境变量的所有目录。如果没有发现所需要的类。它将抛出一个java.lang.ClassNotFoundException异常。

从J2SE1.2起,JVM有三个类加载器:bootstrap class loader,(自启动类加载器) extension class loader,(扩展类加载器)和system class loader(系统类加载器)。三个类加载器中相互存在父子关系:自启动类加载器位于层次结构的最高层,而系统类加载器位于最底层。

自启动类加载器由JVM使用。当你使用java.exe程序时,它就开始工作。这样,它必须使用native code来实现。因为它用来加载JVM所需要的类。它也负责加载所有的核心java类,像:java.lang 和java.io包下的类。自启动类加载器搜索核心类库,像:rt.jar, i18n.jar等。
这些类库的搜索依赖于JVM的版本和操作系统。

扩展类加载器负责加载在标准扩展目录下的类。这样使程序员的操作变得更加容易,因为你只需要把JAR文件按复制到扩展目录下就可以了,这些jar文件就会被自动地搜索。扩展类库在不同的供应商之间是有区别的。Sun的JVM的标准扩展目录是/jdk/jre/lib/ext。
系统类加载器是默认的类加载器,它搜索CLASSPATH环境变量下的目录和JAR文件。

但是,JVM使用哪个类加载器呢?使用角色委托模式,这样会更安全。每次加载一个类,系统类加载器首先会被调用。但是它不会马上加载这个类。它那这个加载任务委派给它的父类加载器,扩展类加载器。而扩展类加载器也把这个任务委派给它的父类加载器,自启动类加载器。自启动类加载器总是给加载一个类的第一次机会来加载它。如果自启动类加载器不能找到需要的类,扩展类加载器就试图去加载这个类。如果扩展类加载器也加载失败,系统类加载器就接手这个加载任务。如果最后系统类加载器也不能找到这个类,就会抛出java.lang.ClassNotFoundException异常。为什么需要以这样的来回方式的加载一个类?

角色委托模式对安全控制十分重要。你可以使用安全管理器来限制访问某一个目录。一些有恶意企图的人可以写一个叫做java.lang.Object的类,它就可以用来访问你在硬盘上的任何目录。因为JVM信任这个java.lang.Object类,所以它不会监控它的活动。结果,如果这个java.lang.Object允许加载,安全管理器很容易被麻痹,这个类就会蒙混过关。幸运的是,因为角色委托模式的存在,这种情况就不会发生。

当一个特殊的java.lang.Object类在程序的某个地方被调用。系统类加载器把这个请求委派给扩展类加载器,然后扩展类加载器委派给自启动类加载器。自启动类加载器搜索它的核心类库,找到标准java.lang.Object,然后实例化它。结果,这个特殊的java.lang.Object将永远不会被加载。

Java中的类加载机制允许你可以通过继承抽象类java.lang.ClassLoader来写自己的类加载器。Tomcat需要一个定制的类加载器的原因就是:

 To specify certain rules in loading classes. 明确某种加载类的规则
 To cache the previously loaded classes. 缓存一个之前加载过的类
 To pre-load classes so they are ready to use. 预加载一个我们将要使用的类

你可能感兴趣的:(java,jvm,tomcat,Web,servlet)