Bootstrap是Tomcat的启动类。
org.apache.catalina.startup.Bootstart类
Bootstrap类是Tomcat的启动类, 下面是其main方法:
public static void main(String args[]) {
// Set the debug flag appropriately
for (int i = 0; i < args.length; i++) {
if ("-debug".equals(args[i]))
debug = 1;
}
// Configure catalina.base from catalina.home if not yet set
if (System.getProperty("catalina.base") == null) {
if (debug >= 1) {
log(getCatalinaHome());
}
System.setProperty("catalina.base", getCatalinaHome());
}
// Construct the class loaders we will need
ClassLoader commonLoader = null;
ClassLoader catalinaLoader = null;
ClassLoader sharedLoader = null;
try {
File unpacked[] = new File[1];
File packed[] = new File[1];
File packed2[] = new File[2];
ClassLoaderFactory.setDebug(debug);
unpacked[0] = new File(getCatalinaHome(),
"common" + File.separator + "classes");
packed2[0] = new File(getCatalinaHome(),
"common" + File.separator + "endorsed");
packed2[1] = new File(getCatalinaHome(),
"common" + File.separator + "lib");
commonLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed2, null);
unpacked[0] = new File(getCatalinaHome(),
"server" + File.separator + "classes");
packed[0] = new File(getCatalinaHome(),
"server" + File.separator + "lib");
catalinaLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
unpacked[0] = new File(getCatalinaBase(),
"shared" + File.separator + "classes");
packed[0] = new File(getCatalinaBase(),
"shared" + File.separator + "lib");
sharedLoader =
ClassLoaderFactory.createClassLoader(unpacked, packed,
commonLoader);
} catch (Throwable t) {
log("Class loader creation threw exception", t);
System.exit(1);
}
Thread.currentThread().setContextClassLoader(catalinaLoader);
// Load our startup class and call its process() method
try {
/**
* 加载一些类,用处如下
* Static class used to preload java classes when using the
* Java SecurityManager so that the defineClassInPackage
* RuntimePermission does not trigger an AccessControlException.
*/
SecurityClassLoad.securityClassLoad(catalinaLoader);
/**
* Instantiate a startup class instance, 即catalina类
*/
if (debug >= 1)
log("Loading startup class");
Class startupClass =
catalinaLoader.loadClass
("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();
// Set the shared extensions class loader
/**
* 设置sharedLoader为Catalina的 parent类加载器
*/
if (debug >= 1)
log("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);
// Call the process() method
if (debug >= 1)
log("Calling startup class process() method");
methodName = "process";
paramTypes = new Class[1];
paramTypes[0] = args.getClass();
paramValues = new Object[1];
paramValues[0] = args;
method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
} catch (Exception e) {
System.out.println("Exception during startup processing");
e.printStackTrace(System.out);
System.exit(2);
}
}
主要流程如下:
- 设置"catalina.base"系统变量,若不存在,则默认为"user.dir"(即项目目录)。
- 创建3个类加载器:commonLoader, catalinaLoader, sharedLoader, 三种类加载器的关系如下:(双亲委派模型)
graph BT catalinaLoader-->commonLoader 应用程序类Loader-->sharedLoader sharedLoader-->commonLoader
- 使用catalinaLoader加载类Catalina,实例化,调用其process()方法。
类加载器的创建方法
上面使用静态方法ClassLoaderFactory.createClassLoader()
来创建一个类加载器,来看看源码
public static ClassLoader createClassLoader(File unpacked[],
File packed[],
ClassLoader parent)
throws Exception {
if (debug >= 1)
log("Creating new class loader");
// Construct the "class path" for this class loader
ArrayList list = new ArrayList();
// Add unpacked directories
if (unpacked != null) {
for (int i = 0; i < unpacked.length; i++) {
File file = unpacked[i];
if (!file.isDirectory() || !file.exists() || !file.canRead())
continue;
if (debug >= 1)
log(" Including directory " + file.getAbsolutePath());
URL url = new URL("file", null,
file.getCanonicalPath() + File.separator);
list.add(url.toString());
}
}
// Add packed directory JAR files
if (packed != null) {
for (int i = 0; i < packed.length; i++) {
File directory = packed[i];
if (!directory.isDirectory() || !directory.exists() ||
!directory.canRead())
continue;
String filenames[] = directory.list();
for (int j = 0; j < filenames.length; j++) {
String filename = filenames[j].toLowerCase();
if (!filename.endsWith(".jar"))
continue;
File file = new File(directory, filenames[j]);
if (debug >= 1)
log(" Including jar file " + file.getAbsolutePath());
URL url = new URL("file", null,
file.getCanonicalPath());
list.add(url.toString());
}
}
}
/** 上面的处理之后,list包含 classes的路径以及所有anpacked的jar包 **/
/**
* 打印示例:
* ClassLoaderFactory: Including directory E:\Myprojects\think-in-java\common\classes
* ClassLoaderFactory: Including jar file E:\Myprojects\think-in-java\common\lib\druid-1.0.12.jar
*/
// Construct the class loader itself
String array[] = (String[]) list.toArray(new String[list.size()]);
StandardClassLoader classLoader = null;
if (parent == null)
classLoader = new StandardClassLoader(array);
else
classLoader = new StandardClassLoader(array, parent);
classLoader.setDelegate(true);
return (classLoader);
}
传入参数为包含.class的文件夹路径,jar包路径,父加载器. 前两个路径中的所有类就是用创建的classLoader来加载的。父加载器可有可无.
关于更细节的classLoader,后续会深入。