下载tomcat 8.0源码可以到tomcat官网去下载 source code distributions 选择zip,下载完新建一个pom.xml就可以导入到eclipse中了。其实知道Tomcat源码就可以把spring Web项目整个运行流程就可以想明白。
一、Tomcat总体结构
一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Cotainer,但可以有多个Connectors,
(因为一个服务可以有多个连接,如同时提供http和https连接,也可以提供相同协议不同端口的接口)
Tomcat最顶层的容器就叫Server,代表整个服务器,Server包含一个或多个的Service.
Service包括了Connector和Container.
Tomcat里的Server由org.apache,catalina.startup.Catalina来管理。Catalina类的三个方法start,stop,load分别管理整个服务器的生命周期。
load方法用于根据conf/server.xml文件创建Server并调用Server的init方法进行初始化,
---》 Catalina类的load()方法详细解释在 (Tomcat源码分析(二))
start方法用于启动服务器,stop方法用于停止服务器,start和stop都调用了Server的start和stop方法。load方法内部调用了Server的init方法。
Server的start方法--->所有的Service中的start方法-->调用所有包含Connector和Container的start方法-》启动了服务器
init和stop方法也是一样。
/**
* Await and shutdown.
*/
public void await() {
getServer().await();
}
Catalina的await方法--》Server的await方法 作用是进入一个循环,让主线程不会退出。
二、Tomcat的启动入口
Catalina类主要负责 具体的管理类,而Bootstrap类是启动的入口(main方法)。
Bootstrap类main方法:
/**
* Main method and entry point when starting Tomcat via the provided
* scripts.
*
* @param args Command line arguments to be processed
*/
public static void main(String args[]) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to prevent
// a range of class not found exceptions.
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();
} 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 t) {
// Unwrap the Exception for clearer error reporting
if (t instanceof InvocationTargetException &&
t.getCause() != null) {
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
如果args参数为空,默认执行start。
main方法内:
bootstrap.init();
具体的实现init()方法:
/**
* Initialize daemon.
*/
public void init() throws Exception {
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;
}
1、初始化ClassLoader(initClassLoaders)
创建commonLoader、catalinaLoader和sharedLoader;
代码如下:
private void initClassLoaders() {
try {
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); //这里如果获取不到server.loader对应的value值就会返回commonLoader。
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
handleThrowable(t);
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}
createClassLoader方法
代码如下:
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
value = replace(value);
List<Repository> repositories = new ArrayList<>();
String[] repositoryPaths = getPaths(value);
for (String repository : repositoryPaths) {
// Check for a JAR URL repository
try {
@SuppressWarnings("unused")
URL url = new URL(repository);
repositories.add(
new Repository(repository, RepositoryType.URL));
continue;
} catch (MalformedURLException e) {
// Ignore
}
// Local repository
if (repository.endsWith("*.jar")) {
repository = repository.substring
(0, repository.length() - "*.jar".length());
repositories.add(
new R