3.按功能看处理流程
将Bootstrap类按其代码分为三部分:
初始化部分,主要是初始化CATALINA_HOME 和CATALINA_BASE变量;
main方法部分一:创建和初始化daemon和catalinaDaemon、创建三个重要类加载器;
main方法部分二:控制Tomcat的启动与停止。
对应流程图如下:

2. 初始化CATALINA_HOME 和CATALINA_BASE
首先看一下Bootstrap类,最早会通过一段代码确定CATALINA_HOME 和CATALINA_BASE两个重要值:
private static final File catalinaBaseFile;
private static final File catalinaHomeFile;
private static final Pattern PATH_PATTERN = Pattern.compile("(\"[^\"]*\")|(([^,])*)");
static {
// Will always be non-null
String userDir = System.getProperty("user.dir");
// Home first
String home = System.getProperty(Constants.CATALINA_HOME_PROP);
//省略部分代码
catalinaHomeFile = homeFile;
System.setProperty(Constants.CATALINA_HOME_PROP, catalinaHomeFile.getPath());
// Then base
String base = System.getProperty(Constants.CATALINA_BASE_PROP);
if (base == null) {
catalinaBaseFile = catalinaHomeFile;
} else {
File baseFile = new File(base);
try {
baseFile = baseFile.getCanonicalFile();
} catch (IOException ioe) {
baseFile = baseFile.getAbsoluteFile();
}
catalinaBaseFile = baseFile;
}
System.setProperty(
Constants.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
}
**CATALINA_HOME:**代表Tomcat安装的根目录,例如/home/tomcat/apache-tomcat-9.0.10或C:\Program Files\apache-tomcat-9.0.10。
**CATALINA_BASE:**表示特定 Tomcat 实例的运行时配置的根。如果您想在一台机器上拥有多个 Tomcat 实例,请使用 CATALINA_BASE 属性。
**默认情况下,CATALINA_HOME 和 CATALINA_BASE 指向同一目录。**如果将属性设置为不同的位置,则 CATALINA_HOME 位置包含静态源,例如 .jar 文件或二进制文件。 CATALINA_BASE 位置包含配置文件、日志文件、部署的应用程序和其他运行时要求。
3. 创建并初始化守护进程daemon和catalinaDaemon
初始化完毕,接着执行的就是main方法,这个方法功能分为两部分:
synchronized (daemonLock) {
if (daemon == null) {
// 在初始化完成之前,不要对daemon赋值
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
//当作为服务正在运行时,如果调用停止方法,这将在一个新线程上进行,以确保使用正确的类加载器,防止出现未找到类的异常。
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
首先创建一个Bootstrap类型的对象,并调用其init()方法进行初始化,直至其初始化完毕,将其赋值给daemon对象。
重点在init方法:
public void init() throws Exception {
//创建并初始化三个ClassLoader
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");
}
//通过反射方式创建
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
// Set the shared extensions class loader
if (log.isDebugEnabled()) {
log.debug("Setting startup class properties");
}
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
catalinaDaemon = startupInstance;
}