tomcat初始化过程
main方法
public static void main(String[] args) {
synchronized(daemonLock) {
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable var5) {
handleThrowable(var5);
var5.printStackTrace();
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
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();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable var7) {
Throwable t = var7;
if (var7 instanceof InvocationTargetException && var7.getCause() != null) {
t = var7.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
初始化启动类,将启动类变成守护线程,根据参数的 方法名称进行加载参数并调用方法。
init方法
public void init() throws Exception {
this.initClassLoaders();
Thread.currentThread().setContextClassLoader(this.catalinaLoader);
SecurityClassLoad.securityClassLoad(this.catalinaLoader);
if (log.isDebugEnabled()) {
log.debug("Loading startup class");
}
Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
if (log.isDebugEnabled()) {
log.debug("Setting startup class properties");
}
String methodName = "setParentClassLoader";
Class<?>[] paramTypes = new Class[]{Class.forName("java.lang.ClassLoader")};
Object[] paramValues = new Object[]{this.sharedLoader};
Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
this.catalinaDaemon = startupInstance;
}
初始化类加载器
private void initClassLoaders() {
try {
this.commonLoader = this.createClassLoader("common", (ClassLoader)null);
if (this.commonLoader == null) {
this.commonLoader = this.getClass().getClassLoader();
}
this.catalinaLoader = this.createClassLoader("server", this.commonLoader);
this.sharedLoader = this.createClassLoader("shared", this.commonLoader);
} catch (Throwable var2) {
handleThrowable(var2);
log.error("Class loader creation threw exception", var2);
System.exit(1);
}
}
init方法调用initClassLoaders方法。我们可以看到该类的类加载器是common,默认的父类加载器是应用类加载器,且server,shared类的父类加载器是common类加载器。
private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception {
// 从根目录下的conf/catalina.properties文件中找到 name.loader 对应的value,这个value就是每个加载器需要加载的所有jar包路径。
// 其中只有commonLoader类加载器会加载tomcat所依赖的jar包,其他两个不会加载。
String value = CatalinaProperties.getProperty(name + ".loader");
if (value != null && !value.equals("")) {
value = this.replace(value);
List<Repository> repositories = new ArrayList();
String[] repositoryPaths = getPaths(value);
String[] arr$ = repositoryPaths;
int len$ = repositoryPaths.length;
for(int i$ = 0; i$ < len$; ++i$) {
String repository = arr$[i$];
try {
new URL(repository);
repositories.add(new Repository(repository, RepositoryType.URL));
} catch (MalformedURLException var11) {
if (repository.endsWith("*.jar")) {
repository = repository.substring(0, repository.length() - "*.jar".length());
repositories.add(new Repository(repository, RepositoryType.GLOB));
} else if (repository.endsWith(".jar")) {
repositories.add(new Repository(repository, RepositoryType.JAR));
} else {
repositories.add(new Repository(repository, RepositoryType.DIR));
}
}
}
return ClassLoaderFactory.createClassLoader(repositories, parent);
} else {
return parent;
}
}
Thread.currentThread().setContextClassLoader(this.catalinaLoader);
SecurityClassLoad.securityClassLoad(this.catalinaLoader);
设置上下文类加载器。
Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
使用catalinaLoader来加载tomcat容器自身的class,并生成catalina的实例。
String methodName = "setParentClassLoader";
Class<?>[] paramTypes = new Class[]{Class.forName("java.lang.ClassLoader")};
Object[] paramValues = new Object[]{this.sharedLoader};
Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
this.catalinaDaemon = startupInstance;
通过反射机制使实例去调用shareLoader的setParentClassLoader方法。