How Tomcat Works 读书笔记 八 载入器 上
Java的类载入器
详细资料见
http://blog.csdn.net/dlf123321/article/details/39957175
http://blog.csdn.net/dlf123321/article/details/40431297
首先说明两个术语
仓库(repository),表示类加载器会在哪里搜索要载入的类;
资源(resource),知道一个类载入器中的DirContext对象,它的文件跟路径指的就是上下文的文件跟路径。
在tomcat中,我们使用了自定义载入器,原因有三:
为了在载入器中指定某些规则;
为了缓存已经载入的类;
为了实现类的预载入;
Loader接口
在加载servlet及相关类的时候,需要遵守一些规则。例如,应用程序中的servelt只能引用部署在web-inf/classes目录下及其子目录下的类,只能访问web-inf/lib目录下的库。
我们在tomcat里说的载入器是指web应用程序载入器,而不仅仅是类载入器。(载入器里面有个类载入器!!!)
载入器应该实现org.apache.catalina.Loader接口,类载入器默认为WebappClassLoader。
package org.apache.catalina; import java.beans.PropertyChangeListener; public interface Loader { public ClassLoader getClassLoader(); public Container getContainer(); //载入器通常与一个context级别的容器相联 public void setContainer(Container container); public DefaultContext getDefaultContext(); public void setDefaultContext(DefaultContext defaultContext); public boolean getDelegate(); //Delegate 代表 委托 public void setDelegate(boolean delegate); //就是类加载器是否会把加载的任务委托给其父类加载器 public String getInfo(); public boolean getReloadable(); //表明是否支持载入器的自动重载 public void setReloadable(boolean reloadable); public void addPropertyChangeListener(PropertyChangeListener listener); public void addRepository(String repository); public String[] findRepositories(); public boolean modified(); //如果容器中的一个或多个类被修改了 modified就会返回true public void removePropertyChangeListener(PropertyChangeListenerlistener); }
默认情况下,在context的标准实现---org.apache.catalina.core.StandContext中是不支持自动重载的,因此要想开启自动重载功能,就需要在server.xml文件中添加一个Context元素,如下
<Context path="/myApp" docBase="myApp" debug="0" reloadable="true"/>
在我们这一节的程序中Catalina 提供了 org.apache.catalina.loader.WebappLoader 作为 Load 接口的实现。WebappLoader 对象包含一个org.apache.catalina.loader.WebappClassLoader 类的实例,该类扩展了Java.netURLClassLoader 类。
当与某个载入器相关联的容器需要使用某个servlet时,或者说就是要调用某个servlet的某个方法时,容器首先会调用载入器的getClassLoader()方法返回类载入器,然后再调用类载入器的loadClass()方法来加载这个servlet类。
uml图如下
WebAppLoader类
当webapploader类的start方法启动时,会完成以下几项工作:
1 创建一个类载入器
2 设置仓库
3 设置类路径
4 设置访问权限
5 启动一个新线程来支持自动重载 (在webapploader的run方法中)
创建类载入器
private WebappClassLoader createClassLoader() throws Exception { //loadClass为字符串 //默认为 private String loaderClass ="org.apache.catalina.loader.WebappClassLoader"; //可通过setLoadClass方法更改 Class<?> clazz = Class.forName(loaderClass); WebappClassLoader classLoader = null; //在构造WebAppLoader时 又构造函数的参数指定 if (parentClassLoader == null) { // Will cause a ClassCast is the class does not extend WCL, but // this is on purpose (the exception will be caught and rethrown) classLoader = (WebappClassLoader) clazz.newInstance(); } else { Class<?>[] argTypes = { ClassLoader.class }; Object[] args = { parentClassLoader }; Constructor<?> constr = clazz.getConstructor(argTypes); classLoader = (WebappClassLoader) constr.newInstance(args); } return classLoader; }
当然我们可以通过setLoadClass来改变类加载器的实现,不过
(WebappClassLoader) constr.newInstance(args);
所以,我们自定义的类也要继承WebappClassLoader。
设置仓库
调用setRepositories,设置WEB-ING/classes目录与WEB-INF/lib目录
设置类路径
和jasper JSP编译器有关
设置访问权限
setPermissions 可以设置类载入器访问相关路径的权限。例如只能访问WEB-INf/classes目录与WEB-INF/lib目录
开启新线程执行类的重新载入
public void run() { if (debug >= 1) log("BACKGROUND THREAD Starting"); // Loop until the termination semaphore is set //整段代码包含在while循环中 //在前面threadDone已经被设置为false //直到程序关闭时,threadDone才会变为true while (!threadDone) { // Wait for our check interval threadSleep(); if (!started) break; try { // Perform our modification check if (!classLoader.modified()) continue; } catch (Exception e) { log(sm.getString("webappLoader.failModifiedCheck"), e); continue; } // Handle a need for reloading notifyContext(); break; } if (debug >= 1) log("BACKGROUND THREAD Stopping"); } private void threadSleep() { //让程序休眠一段时间 时间由checkInterval指定 try { Thread.sleep(checkInterval * 1000L); } catch (InterruptedException e) { ; } }
checkInterval,是每隔若干秒来检查一次容器中的类是否有更改!
一旦有更改classLoader.modified()会返回true,直接调用notifyContext();
private void notifyContext() { WebappContextNotifier notifier = new WebappContextNotifier(); (new Thread(notifier)).start(); } protected class WebappContextNotifier implements Runnable { /** * Perform the requested notification. */ public void run() { ((Context) container).reload(); } }
WebappContextNotifier是webapploader的内部类。
这里重新启了一个线程,避免了拥塞。
WebappClassLoader类
该类继承自java.net.URLClassLoader类,后者我们在前面章节已经用过;
WebappClassLoader类的设计考虑了安全与优化两个方面。
WebappClassLoader 类不允许一些特定的类被加载。这些类被存储在一个 String 类型的数组中,现在仅仅有一个成员。
private static final String[] triggers = {
"javax.servlet.Servlet" // Servlet API
};
另外在委派给系统加载器的时候,也不允许加载某些特殊的包的类或者它的子包:
private static final String[] packageTriggers = { "javax", // Java extensions "org.xml.sax", // SAX 1 & 2 "org.w3c.dom", // DOM 1 & 2 "org.apache.xerces", // Xerces 1 & 2 "org.apache.xalan" // Xalan };
类缓存
为了达到更好的性能,会缓存已经载入的类,这样一来下次在使用这个类的时候,就不用再起加载了。
缓存分两级,一级在本地执行,由webappclassloader实例来管理。
此外,java.lang.ClassLoader类也会维护一个Vector对象,保存已经载入的类,此时缓存由父类管理。
每个由WebappClassLoader载入的类,都视为资源。是org.apache.catalina.loader.ResourceEntry类的实例,里面包含所代表的class文件的字节流,最后一次修改时间等等:
package org.apache.catalina.loader; import java.net.URL; import java.security.cert.Certificate; import java.util.jar.Manifest; public class ResourceEntry { public long lastModifled = -1; // Binary content of the resource.public byte[] binaryContent = null; public Class loadedClass = null; // URL source from where the object was loaded. public URL source = null; // URL of the codebase from where the object was loaded. public URL CodeBase = null; public Manifest manifest = null; public Certificate[] certificates = null; }
所有缓存的源被存放在一个叫做 resourceEntries 的 HashMap 中,键值为载入的资源名称,所有找不到的资源都被放在一个名为 notFoundResources 的 HashMap 中。
至于真正的加载类,我们放在下一节说。
参考资料
http://my.oschina.net/xianggao/blog/70826
How Tomcat Works 读书笔记 八 载入器 上的更多相关文章
- how tomcat works 读书笔记 八 载入器下
载入类 我们看看之前的文章,这一节就从SimpleWrapper的loadServlet讲起. SimpleWrapper.java如下(省略了try catch及其他部分代码) public Ser ...
- How Tomcat Works 读书笔记 八 加载器 上
Java的类加载器 具体资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...
- How tomcat works 读书笔记十二 StandardContext 上
在tomcat4中,StandardContext.java是最大的一个类,有117k.废话不说,开始分析吧. 其实要分析StandardContext,也就主要分析两个方法,一个start,一个in ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- how tomcat works 读书笔记四 tomcat的默认连接器
事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...
- How tomcat works 读书笔记十二 StandardContext 下
对重载的支持 tomcat里容器对重载功能的支持是依靠Load的(在目前就是WebLoader).当在绑定载入器的容器时 public void setContainer(Container cont ...
- how tomcat works 读书笔记 十一 StandWrapper 上
方法调用序列 下图展示了方法调用的协作图: 这个是前面第五章里,我画的图: 我们再回顾一下自从连接器里 connector.getContainer().invoke(request, resp ...
- How tomcat works 读书笔记十七 启动tomcat 上
一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...
- How tomcat works 读书笔记十五 Digester库 下
在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...
随机推荐
- Linux动态频率调节系统CPUFreq之三:governor
在上一篇文章中,介绍了cpufreq的core层,core提供了cpufreq系统的初始化,公共数据结构的建立以及对cpufreq中其它子部件提供注册功能.core的最核心功能是对policy的管理, ...
- ORACLE EBS 表空间控制
--1G=1024MB --1M=1024KB --1K=1024Bytes --1M=11048576Bytes --1G=1024*11048576Bytes=11313741824Bytes S ...
- FORM开发实现动态LOV
方法一.设置lov的记录组 IF :mat_trx.trx_action_id = 1 THEN set_lov_property('lot_number',group_name,'lot_issue ...
- C控制台实现模拟平抛运动算法
平抛运动这个相信读了高中物理都知道这个概念了,详细的我就不说了,不明白的看看百度: 平抛运动 接下来看看用控制台实现的平抛运动算法: #include <stdio.h> #include ...
- iOS开发之*.a静态库注意事项
以*.a静态库的形式引入工程的(比如:libUploadLib.a),*.a里面的class有category形式实现时,除了在工程Target的 Build Phases里面的 Link Binar ...
- 【iOS 开发】iOS 开发 简介 (IOS项目文件 | MVC 模式 | 事件响应机制 | Storyboard 控制界面 | 代码控制界面 | Retina 屏幕图片适配)
一. iOS 项目简介 1. iOS 文件简介 创建一个 HelloWorld 项目, 在这个 IOS 项目中有四个目录 : 如下图; -- HelloWorldTests 目录 : 单元测试相关的类 ...
- scala学习笔记1(表达式)
<pre name="code" class="plain">//Scala中的 main 函数需要存在于 object 对象中,我们需要一个obj ...
- hive支持in用法是从0.3.2版本后
写hive 用in 如分时段,分类型,分平台统计点击量 select substr(createtime,12,2) hour,logtype,os_id,count(*) from wizad_ ...
- Dynamics CRM CRM Explorer missing from Visual Studio 2012
CRMSDK中提供的develop toolkit工具比较适合初级开发者或者是多人团队的开发,在代码版本控制及部署上均有明显的优势. 但今天在装完这个工具后,打开vs2012可以新建一个package ...
- 【翻译】将Ext JS Grid转换为Excel表格
原文:Converting an Ext 5 Grid to Excel Spreadsheet 稍微迟来的礼物--Ext JS Grid转为Excel代码,现在支持Ext JS 5! 功能包括: - ...