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 中。
至于真正的载入类,我们放在下一节说。
參考资料
How Tomcat Works 读书笔记 八 加载器 上的更多相关文章
- How Tomcat Works 读书笔记 八 载入器 上
Java的类载入器 详细资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...
- how tomcat works 读书笔记 八 载入器下
载入类 我们看看之前的文章,这一节就从SimpleWrapper的loadServlet讲起. SimpleWrapper.java如下(省略了try catch及其他部分代码) public Ser ...
- How tomcat works 读书笔记十五 Digester库 上
Digester库 在前面的几个章节里,我们对tomcat里各个组件的配置完全是使用写硬编码的形式完成的. 如 Context context = new StandardContext(); Loa ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- JVM笔记11-类加载器和OSGI
一.JVM 类加载器: 一个类在使用前,如何通过类调用静态字段,静态方法,或者new一个实例对象,第一步就是需要类加载,然后是连接和初始化,最后才能使用. 类从被加载到虚拟机内存中开始,到卸载出内存为 ...
- how tomcat works 读书笔记四 tomcat的默认连接器
事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...
- How Tomcat Works读书笔记三-------连接器
几个概念 HttpServlet,Servlet Servlet是一个接口,定义了一种网络服务,我们所有的servlet都要实现它(或它的子类) HttpServlet是一个抽象类,它针对的就是htt ...
- How tomcat works 读书笔记十七 启动tomcat 上
一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...
- How tomcat works 读书笔记十五 Digester库 下
在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...
随机推荐
- ZigBee PHY层
1. 介绍 ZigBee PHY层,即IEEE 802.15.4 PHY层,这里主要介绍了802.15.4-2003版本 PHY主要实现了如下功能 - 启动和关闭RF收发器 - 信道能量检测(Chan ...
- 【C++】const、volatile不能修饰没有this指针的成员函数
一般所有的成员函数都只有一个复本,当不同的对象调用成员函数时,为了区分是哪个成员在调用,会传入this指针. 当调用有const.volatile修饰的成员函数时,会相应的传入一个const.vola ...
- 磁盘挂载MOUNT 445问题集
挂载磁盘mount -t cifs -o username="Administrator",password="123@qq" //192.168.100.4/ ...
- 团队开发中git分支的使用
1.Github上保持两个分支:master和develop. master是主分支,对项目进行tag或发布版本等操作,都必须在该分支上进行.最好设为不可提交只能合并的. develop是开发分支,从 ...
- CodeForces 669A
链接:http://codeforces.com/problemset/problem/669/A 本文链接:http://www.cnblogs.com/Ash-ly/p/5442950.html ...
- Cent OS 运行 Cuberite
Cuberite 是一个轻量级的Minecraft服务端,由C++编写,性能比Mojang等等用java写的高很多. 在腾讯云的最低端VPS上,用Spigot建服的话,从主世界传送到下界用时要五六秒的 ...
- [BZOJ4772]显而易见的数论(数论)
4772: 显而易见的数论 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 76 Solved: 32[Submit][Status][Discuss ...
- [BZOJ 3571] 画框
Link: BZOJ 3571 传送门 Solution: 和 BZOJ2395 的建模完全相同,(BZOJ2395 题解传送门) 仅仅是将其中的基础问题由最小生成树改成了二分图最大完美匹配 只要将原 ...
- SD 一轮集训 day1 carcar
可以发现每条边只能选一次或者两次,并且最后每个点的度数(∑邻接边选的次数和)都是偶数(代表有欧拉回路). 然后根据题意列一个 n 行 m+1 列的01矩阵,每一行代表一个异或方程组(每个点的度数是偶数 ...
- [Contest20180426]校门外的树
$\newcommand{\align}[1]{\begin{align*}#1\end{align*}}$题意:对于一个排列$p_{1\cdots n}$构造一个图,如果$i\lt j$且$p_i\ ...