本文目的是总结tomcat的类Bootstrap和Catalina的在启动中的动作。由于tomcat是通过组件方式进行注册及生命周期的统一管理,所以对各不同组件的生命周期及动作源码解析会在后面的文章中进行说明。
关于tomcat源码导入可以参考我的上一篇文章点击打开链接。
文章中对于启动部分源码解析,需要对tomcat部分基础知识进行了解:
catalina.properties配置文件中参数功能
package.access:针对访问某个package内的代码,Java Security Manager机制提供了安全属性package.access,可以指定哪些包需要受到权限保护,会进行checkPackageAccess验证。
package.definition:同package.access,会进行checkPackageDefinition验证。
common.loader:tomcat自身和各web服务都会用到的类
server.loader:tomcat自身会用到的类
shared.loader:各web服务会用到的类
tomcat.util.buf.StringCache.*:字符缓存配置
正文:
Tomcat正常启动通过bin目录下startup间接调用catalina,并从catalina中首先执行Bootstrap的main方法,之后通过反射启动Catalina中的方法进行tomcat启动(无论是批处理文件和sh文件这部分处理过程都一样)。
注:通过批处理文件和sh文件启动时会重设置classpath,只加载tomcat配置中允许的jar。
Tomcat6源码启动可以通过Catalina类的main方法;也可以通过Bootstrap中的main()函数开始。Bootstrap类实质上是通过反射的方法去执行Catalina中的函数。Catalina的main方法似乎只是用于调试的,本人目前并没有发现有其他调用的地方。
Bootstrap.java启动代码如下:
public static void main(String args[]) {
if (daemon == null) {
daemon = new Bootstrap();
try {
daemon.init();
} catch (Throwable t) {
t.printStackTrace();
return;
}
}
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
由于刚开始只关注启动部分,所以使用默认command="start",总结启动执行顺序如下:
daemon.init();
daemon.setAwait(true);
daemon.load(args);
daemon.start();
在init()方法中,执行功能为
1、初始化catalina.home和catalina.base两个位置,相当于找到tomcat目录的根目录。
2、初始化commonLoader、catalinaLoader、sharedLoader;它们对应的是catalina.properties中的common.loader、server.loader、shared.loader;顺便也完成了catalina.properties的配置加载
3、为当前启动服务设置catalinaLoader;并进行安全验证;
4、初始化org.apache.catalina.startup.Catalina利用反射调用它的setParentClassLoader设置sharedLoader;(设置的parentClassLoader的原因和用处暂不完全清楚,看源码估计会在server.xml加载部分会使用到)。
代码如下:
public void init()
throws Exception
{
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
initClassLoaders();
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class")