Tomcat研究之ClassLoader
在研究Tomcat之前,一般是借用现有的UML工具分析Tomcat整体结构,但要分析Tomcat的流程就必须从分析Tomcat的StartUp入手。Tomcat的启动是从解析bat文件开始,bat文件最终调用org.apache.catalina.startup.Bootstrap开始类的加载。
一.Tomcat的ClassLoader:
TOMCAT自己的类载入器(ClassLoader)
+---------------------------+
| Bootstrap |
| | |
| System |
| | |
| Common |
| / / |
| Catalina Shared |
+---------------------------+
其中:
- Bootstrap - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar
- System
1.载入$CATALINA_HOME/bin/bootstrap.jar 初始化Tomcat,执行Main方法
2. $JAVA_HOME/lib/tools.jar Sun的工具类,包括编译Jsp为Servlet的工具类
- Common 这个目录下的类虽然对TOMCAT和所有的WEB APP都可见.但是Web App的类不应该
放在这个目录下,所有未打包的Class都在$CATALINA_HOME/common/classes下,所
有打包的jar都在
$CATALINA_HOME/commons/endorsed和$CATALINA_HOME/common/lib下,默认情况会
包含以下几个包:
1. jndi.jar JNDI API接口,这个包仅在Java1.2时候装入,1.3以后的版本JDK已
自动装入.
2. naming-common.jar JNDI接口实现类,Tomcat用这些类在内存中使用Context.
3. naming-resources.jar JNDI实现,Tomcat用它们定位Web App的静态资源.
4. servlet.jar Servlet,Jsp API
5. xerces.jar XML解析器,特定的Web App可以在自己的/WEB-INF/lib 中覆盖.
- Catalina 装入Tomcat实现所有接口的类,这些类对Web App是完全不可见的,所有未打包的类在
$CATALINA_HOME/server/classes所有jar包在$CATALINA_HOME/server/lib下.一
般情况该ClassLoader将Load下面几个包:
1. catalina.jar Servlet容器的Tomcat实现包
2. jakarta-regexp-X.Y.jar 正则表达式,请求过滤时使用
3. servlets-xxxxx.jar Servlet支持包
4. tomcat-coyote.jar Tomcat的Coyote连接实现包
5. tomcat-jk.jar Web Server绑定包,允许Tomcat绑定Apache等作为Web Server
6. tomcat-jk2.jar 功能同上
7. tomcat-util.jar Tomcat工具类,可能被一些Connector用到
8. tomcat-warp.jar 用于Apache Server包
- Shared 载入所有WEB APP都可见的类,对TOMCAT不可见. 所有未打包的类在
$CATALINA_HOME/shared/classes所有jar包在$CATALINA_HOME /lib下.
默认情况包含下面几个包:
1. jasper-compiler.jar Jsp编译器,编译Jsp为Servlet
2. jasper-runtime.jar Jsp(已编译成Servlet)运行支持包
3. naming-factory.jar 支持Web App使用JNDI的封装包
-WebAppX Web App ClassLoader,当Web App被部署是该ClassLoader被创建.所有class都在
WEB-INF/classes下,所有jar在WEB-INF/lib下.
特别注意WEB APP自己的ClassLoader的实现与众不同:
它先试图从WEB APP自己的目录里载入,如果失败则请求父ClassLoader的代理
这样可以让不同的WEB APP之间的类载入互不干扰.另,Tomcat Server使用的是Catalina
ClassLoader,一般的Web App使用的是WebApp ClassLoader.
二. org.apache.catalina.startup.Bootstrap
该类是Tomcat的执行入口点,我们着重分析下面两个方法:
1. initClassLoaders,创建ClassLoader层次.
private void initClassLoaders() {
try {
ClassLoaderFactory.setDebug(debug);
//创建common ClassLoader,没有父ClassLoader
commonLoader = createClassLoader("common", null);
//创建catalina ClassLoader,父ClassLoader为common
catalinaLoader = createClassLoader("server", commonLoader);
//创建shared ClassLoader, 父ClassLoader为common
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
log("Class loader creation threw exception", t);
System.exit(1);
}
}
2. createClassLoader,负责具体的创建工作
在$CATALINA_HOME/conf/catalina.properties中定义了common, server, shared
ClassLoader载入类的路径及一些包的安全权限.
//common载入类的路径
common.loader=${catalina.home}/common/classes,
${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
//server载入类的路径
server.loader=${catalina.home}/server/classes,
${catalina.home}/server/lib/*.jar
//shared载入类的路径
shared.loader=${catalina.base}/shared/classes,
${catalina.base}/shared/lib/*.jar
/**
*param name:Load Name
*param parent:父Loader
*classLoader的资源分三种:
*1.未打包的classes,一般是一个目录
*2.打包的jar目录
*3.网络资源,一般是网上的一个jar包 (Applet经常用到这样的loader)
*/
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
//从catalina.properties中取得改Loader的配置信息
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
//classes目录
ArrayList unpackedList = new ArrayList();
//jar目录 </