您的位置:首页 > 运维架构 > Tomcat

Tomcat的加载器(standard web application loader)

2016-02-18 14:54 337 查看
Tomcat加载一个servlet容器需要一个特定的容器,而不是使用系统的加载器。

这个是为什么呢?

1.安全考虑:使用系统的加载器的话,servlet就可以进入java虚拟机的classpath环境下面的任何类和类库,这样会带来安全隐患。而servlet只可以访问WEB-INF/目录下的类和部署在WEB-INF/lib下的类库。

2. 加载器实现了org.apache.catalina.loader.Reloader接口。也就是说,在servlet发生变化的时候,被改动的时候会重新加载。

首先,先说一下java的加载器

在每次创建一个Java类的实例时候,必须先将该类加载到内存中。Java虚拟机(JVM)使用类加载器来加载类。Java加载器在Java核心类库和CLASSPATH环境下面的所有类中查找类。如果需要的类找不到,会抛出java.lang.ClassNotFoundException异常。 JVM使用了三种类加载器:bootstrap类加载器、extension类加载器和systen类加载器。

这三个加载器是父子关系,其中bootstrap类加载器在顶端,而system加载器在结构的最底层。 

1.bootstrap类加载器--用于引导JVM,一旦调用java.exe程序,bootstrap类加载器就开始工作。因此,它必须使用本地代码实现,然后加载JVM需要的类到函数中。另外,它还负责加载所有的Java核心类,例如java.lang和java.io包。另外bootstrap类加载器还会查找核心类库如rt.jar、i18n.jar等,这些类库根据JVM和操作系统来查找。

2.extension类加载器负责加载标准扩展目录下面的类。这样就可以使得编写程序变得简单,只需把JAR文件拷贝到扩展目录下面即可,类加载器会自动的在下面查找。不同的供应商提供的扩展类库是不同的,Sun公司的JVM的标准扩展目录是/jdk/jre/lib/ext。

3.system加载器是默认的加载器,它在环境变量CLASSPATH目录下面查找相应的类。 

委派模型(delegatio model)

每次一类需要加载,system类加载器首先调用。但是,它不会马上加载类。相反,它委派该任务给它的父类extension类加载器。extension类加载器也把任务委派给它的父类bootstrap类加载器。因此,bootstrap类加载器总是首先加载类。如果bootstrap类加载器不能找到所需要的类的extension类加载器会尝试加载类。如果扩展类加载器也失败,system类加载器将执行任务。如果系统类加载器找不到类,一个java.lang.ClassNotFoundException异常。为什么需要这样的往返模式?
委派模型对于安全性是非常重要的。如你所知,可以使用安全管理器来限制访问某个目录。现在,恶意的意图有人能写出一类叫做java.lang.Object,可用于访问任何在硬盘上的目录。因为JVM的信任java.lang.Object类,它不会关注这方面的活动。因此,如果自定义java.lang.Object被允许加载的安全管理器将很容易瘫痪。幸运的是,这将不会发生,因为委派模型会阻止这种情况的发生。下面是它的工作原理。 当自定义java.lang.Object类在程序中被调用的时候,system类加载器将该请求委派给extension类加载器,然后委派给bootstrap类加载器。这样bootstrap类加载器先搜索的核心库,找到标准java.lang.Object并实例化它。这样,自定义java.lang.Object类永远不会被加载.

Tomcat在这个基础上做了扩展

1. 要制定类加载器的某些特定规则 

2. 缓存以前加载的类 

3. 事先加载类以预备使用

Loader接口

一个Tomcat类加载器表示一个Web应用程序加载器,而不是一个类加载器。一个加载器必须实现org.apache.catalina.Loader接口。加载器的实现使用定制的类加载器org.apache.catalina.loader.WebappClassLoader。可以使用Loader接口的getClassLoader方法获取一个网络加载器ClassLoader。

值得一提的是Loader接口定义了一系列方法跟库协作。Web应用程序的WEB-INF/classes 和 WEB-INF/lib目录作为库添加上。Loader接口的addReposity方法用于添加一个库,findRepositories方法用于返回一个所有库的队列.

一个Tomcat的加载器通常跟一个上下文相关联,Loader接口的和getContainer及setContainer方法是建立此关联。一个加载器还可以支持重新加载,如果在上下文中的一个或多个类被修改。新类将被重新加载而不需要不重新启动Tomcat加载。为了达到重新加载的目的,Loader接口有修改方法。在加载器的实现中,如果在其库中一个或多个类别已被修改,modeify方法必须返回true,因此需要重新加载。一个加载器自己进行重新加载,而是调用上下文接口的重载方法。另外两种方法,setReloadable和getReloadable,用于确定加载器中是否可以使用重加载。默认情况下,重载机制并未启用。因此,要使得上下文启动重载机制,需要在server.xml文件添加一些元素如下:

<Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>

WebappLoader

org.apache.catalina.loader.WebappLoader类是Loader接口的实现,它表示一个web应用程序的加载器,负责给web应用程序加载类。WebappLoader创建一个org.apache.catalina.loader.WebappClassLoader类的实例作为它的类加载器。像其他的Catalina组件一样,WebappLoader实现了org.apache.catalina.Lifecycle接口,关联容器启动和停止。WebappLoader类还实现了java.lang.Runnable接口,所以可以通过一个线程来重复的调用modified方法,如果modified方法返回true,WebappLoader实例通知它的关联容器。类通过上下文重新加载自己,而不是WebappLoader。

WebappLoader类的start方法被调用的时候,将会完成下面几项重要任务:

1. 创建一个类加载器 

2. 设置库 

3. 设置类路径 

4. 设置访问权限 

5. 开启一个新线程用来进行自动重载

开启自动重载线程

WebappLoader支持自动重载,如果WEB-INF/classes或者WEB-INF/lib目录被重新编译过,在不重启Tomcat的情况下必须自动重新载入这些类。为了实现这个目的,WebappLoader有一个单独的线程每个x秒会检查源的时间戳。x的值由checkInterval变量定义,它的默认值是15,也就是每隔15秒会进行一次检查是否需要自动重载。该类还提供了两个方法getCheckInterval和setCheckInterval方法来访问或者设置checkInterval的值。

WebappClassLoader

类org.apache.catalina.loader.WebappClassLoader表示在一个web应用程序中使用的加载器。WebappClassLoader类继承了java.net.URLClassLoader类,该类在前面章节中用于加载Java类。

WebappClassLoader被可以的进行了优化和安全方面的考虑。例如它缓存了以前加载的类以改进性能,下一次收到第一次没有找到的类的请求的时候,可以直接抛出ClassNotFound异常。WebappClassLoader在源列表以及特定的JAR文件中查找类。
处于安全性的考虑,WebappClassLoader类不允许一些特定的类被加载。这些类被存储在一个String类型的数组中,现在仅仅有一个成员。

摘自:how tomcat works
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: