先大致浏览一下整个启动过程吧。下面是org.apache.catalina.startup.Bootstrap的main函数。
我在eclipse调用的是start的命令,也就是传入main的参数是start
// 初始化, 构建org.apache.catalina.startup.Catalina实例,并赋值给catalinaDaemon
bootstrap.init();
// 把刚刚创建并初始化好的bootstrap赋值给bootstrap daemon object used by main.
daemon = bootstrap;
// 设置catalinaDaemon的await为true
daemon.setAwait(true);
// 将main的参数传递给org.apache.catalina.startup.Catalina实例:catalinaDaemon,调用catalinaDaemon的load方法
daemon.load(args);
// 调用catalinaDaemon的start来启动tomcat
daemon.start();
可见,Bootstrap只是一个接待员,真正管事的是org.apache.catalina.startup.Catalina实例:catalinaDaemon。下面再细看上面的几步:
[size=medium]1. bootstrap.init()[/size]
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
// 初始化class loader
initClassLoaders();
// 初始化3个class loader,commonLoader是parent,catalinaLoader和sharedLoader是child
// 为当前的线程设置class loader为catalinaLoader
Thread.currentThread().setContextClassLoader(catalinaLoader);
// 用catalinaLoader来加载Catalina类,并创建一个实例
Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// 将sharedLoader设置为startupInstance的父loader,利用反射,如同执行了下面这么一句:
startupInstance.setParentClassLoader(sharedLoader)
// 因为Catalina有这么一个方法。
// 将建好的startupInstance赋值给catalinaDaemon
catalinaDaemon = startupInstance;
因此,初始话的过程,主要就是设置了Catalina path,初始化了三个class loader,并设置了他们的关系,
构建一个最终是为了org.apache.catalina.startup.Catalina的实例,并赋值给catalinaDaemon。以被后面调用。
[size=medium]2. daemon.load(args)也即catalinaDaemon.load, 创建并初始化一个新的服务器实例[/size]
// 初始化目录,命名
initDirs();
initNaming();
// 创建并执行server.xml解析器
Digester digester = createStartDigester();
// 将catalinaDaemon注入server组件(org.apache.catalina.core.StandardServer实例)
getServer().setCatalina(this);
// 重定向System输出流out和错误流err
initStreams();
// 启动这个新server组件
getServer().init();
// 输出服务器初始化时间,也即启动时间,因为后面在Bootstrap最后一步就直接调用start命令了。
[size=medium]3. daemon.start(); 也即是catalinaDaemon.start()[/size]
// 启动上面初始化好的server
getServer().start();
// 注册关闭钩子,这样你才能调用shutdown命令停止server
Runtime.getRuntime().addShutdownHook(shutdownHook);
// 等待关闭命令,监听关闭命令的port是8005
大致的启动过程也就是这样了,还算比较清楚。接下来抽空看看getServer().init();
我在eclipse调用的是start的命令,也就是传入main的参数是start
// 初始化, 构建org.apache.catalina.startup.Catalina实例,并赋值给catalinaDaemon
bootstrap.init();
// 把刚刚创建并初始化好的bootstrap赋值给bootstrap daemon object used by main.
daemon = bootstrap;
// 设置catalinaDaemon的await为true
daemon.setAwait(true);
// 将main的参数传递给org.apache.catalina.startup.Catalina实例:catalinaDaemon,调用catalinaDaemon的load方法
daemon.load(args);
// 调用catalinaDaemon的start来启动tomcat
daemon.start();
可见,Bootstrap只是一个接待员,真正管事的是org.apache.catalina.startup.Catalina实例:catalinaDaemon。下面再细看上面的几步:
[size=medium]1. bootstrap.init()[/size]
// Set Catalina path
setCatalinaHome();
setCatalinaBase();
// 初始化class loader
initClassLoaders();
// 初始化3个class loader,commonLoader是parent,catalinaLoader和sharedLoader是child
commonLoader = createClassLoader("common", null);
if( commonLoader == null ) {
// no config file, default to this loader - we might be in a 'single' env.
commonLoader=this.getClass().getClassLoader();
}
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
// 为当前的线程设置class loader为catalinaLoader
Thread.currentThread().setContextClassLoader(catalinaLoader);
// 用catalinaLoader来加载Catalina类,并创建一个实例
Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// 将sharedLoader设置为startupInstance的父loader,利用反射,如同执行了下面这么一句:
startupInstance.setParentClassLoader(sharedLoader)
// 因为Catalina有这么一个方法。
/**
* Set the shared extensions class loader.
*
* @param parentClassLoader The shared extensions class loader.
*/
public void setParentClassLoader(ClassLoader parentClassLoader) {
this.parentClassLoader = parentClassLoader;
}
// 将建好的startupInstance赋值给catalinaDaemon
catalinaDaemon = startupInstance;
因此,初始话的过程,主要就是设置了Catalina path,初始化了三个class loader,并设置了他们的关系,
构建一个最终是为了org.apache.catalina.startup.Catalina的实例,并赋值给catalinaDaemon。以被后面调用。
[size=medium]2. daemon.load(args)也即catalinaDaemon.load, 创建并初始化一个新的服务器实例[/size]
// 初始化目录,命名
initDirs();
initNaming();
// 创建并执行server.xml解析器
Digester digester = createStartDigester();
// 将catalinaDaemon注入server组件(org.apache.catalina.core.StandardServer实例)
getServer().setCatalina(this);
// 重定向System输出流out和错误流err
initStreams();
// 启动这个新server组件
getServer().init();
// 输出服务器初始化时间,也即启动时间,因为后面在Bootstrap最后一步就直接调用start命令了。
[size=medium]3. daemon.start(); 也即是catalinaDaemon.start()[/size]
// 启动上面初始化好的server
getServer().start();
// 注册关闭钩子,这样你才能调用shutdown命令停止server
Runtime.getRuntime().addShutdownHook(shutdownHook);
// 等待关闭命令,监听关闭命令的port是8005
if (await) {
await();
stop();
}
大致的启动过程也就是这样了,还算比较清楚。接下来抽空看看getServer().init();