前文已经从架构层次讲解了tomcat框架设计,以及tomcat使用,以及每个模块的作用,以及各功能模块之间的关系。
下面是Tomcat 9 架构的一个启用的架构流程图:
1、Bootstrap类
主要是其中的 main 启动方法:
public static void main(String args[]) {
LogPropertiesTest.debug("1、BootStrap 启动开始 ");
synchronized (daemonLock) {
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();
// Bootstrap类首先会创建一个本类对象, 然后调用init()方法进行初始化. 执行完init() 方法后会判断启动参数的值,
// 由于我们采取默认的启动方式, 所以main方法的参数是start, 会进入下面的判断代码块
// 此处是重要入口。
} else if (command.equals("start")) {
daemon.setAwait(true);
// 可以看到在设置等待后, 调用了本类对象的load()方法. 我们跟进查看load()方法的源码.
daemon.load(args);
LogPropertiesTest.debug("BootStrap : 调用 Bootstrap 的方法 start() ");
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);
}
}
其中比较重要的地方
bootstrap.init(); 调用初始化
daemon.load(args); 调用load加载信息 --- 》 此处会调用Catalina的load方法。
daemon.start(); 调用开始方法 ----》 此处会调用Catalina的start方法。
2、Catalina类 的调用
Catalina类的load()方法:
/**
* 开启一个新的 server 。 Start a new server instance.
* 关键的有2部分, 111111. 就是 第一步创建Digester . 222222.第二步 在2处进行了解析
*/
public void load() {
LogPropertiesTest.debug("7、Catalina : 调用 Catalina 的方法 load() ");
// 判断是否第一场加载
if (loaded) {
return;
}
loaded = true;
long t1 = System.nanoTime();
// Java输入输出临时路径
initDirs();
// Before digester - it may be needed
initNaming();
// Create and execute our Digester 类似 一个解析 server.xml 的解析器。
// tomcat使用Digester类来解析相关的xml文件,包括web.xml和server.xml,我们先讨论下server.xml .
// 1111111111111111.
Digester digester = createStartDigester();
..........
/// 2222222222.
inputSource.setByteStream(inputStream);
digester.push(this);
...........
// 解析 server.xml 解析 rules,通过rules创建对象执行对象。此处内部调用Server的set 方法,以及其它规则。
digester.parse(inputSource);
...........
// Start the new server
//一系列的初始化, 首先是Server的初始化 org.apache.catalina.core.StandardServer
//第二是Service的初始化 org.apache.catalina.core.StandardService
// StandardServer 继承自 LifecycleBase ,调用 LifecycleBase init方法。
getServer().init();
..........
}
源码中比较重要的几个步骤:
// Create and execute our Digester 类似 一个解析 server.xml 的解析器。
// tomcat使用Digester类来解析相关的xml文件,包括web.xml和server.xml,我们先讨论下server.xml .
Digester digester = createStartDigester();
// 解析 server.xml 解析 rules,通过rules创建对象执行对象。此处内部调用Server的set方法,以及其它规则。
digester.parse(inputSource); ----------》 此处会通过Digester的parse机制将StandardServer对象设置到Catalina对象中。
//一系列的初始化,首先是Server的初始化 org.apache.catalina.core.StandardServer
//第二是Service的初始化 org.apache.catalina.core.StandardService
// StandardServer 继承自 LifecycleBase ,调用 LifecycleBase init方法。
getServer().init();
Catalina类的start()方法:
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
// Start the new server
try {
// 首先是Server的 start 方法 org.apache.catalina.core.StandardServer
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
......
}
最重要的调用部分就是
// 首先是Server的 start 方法 org.apache.catalina.core.StandardServer
getServer().start(); 调用 StandardServer的start()方法。
3、Server类的调用
首先看一下Server的init方法。
server的类继承关系如下图所示:
其中类中的方法如下,你可以看到 调用StandardServer中的 init()或者start()方法其实都是在调用LifecycleBase类中的方法,然后LifecycleBase中的init()或者start()方法 调用类具体实现子类的
initInternal();
startInternal();方法,此处应该使用了 java的模板模式。
StandardServer类的initInternal()方法
@Override
protected void initInternal() throws LifecycleException {
// Register global String cache
// Note although the cache is global, if there are multiple Servers
// present in the JVM (may happen when embedding) then the same cache
// will be registered under multiple names
onameStringCache = register(new StringCache(), "type=StringCache");
// Register the MBeanFactory
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
globalNamingResources.init();
.......
// Initialize our defined Services
// 初始化 services org.apache.catalina.core.StandardService
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
最重要的还是最后哪一行
services[i].init(); 直接变成调用 Service的init()方法了。
StandardServer类的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
// 初始化 services org.apache.catalina.core.StandardService
services[i].start();
}
}
}
向下一个流程进行,则继续调用service的方法。
services[i].start();
4、Service类 的调用
首先还是看一下service类的一个继承关系:其实跟上面 Server类 的实现类似。
StandardService类的startInternal()方法
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
if (engine != null) {
// 初始化
engine.init();
}
// Initialize any Executors
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
// Executor 初始化
executor.init();
}
// Initialize mapper listener
mapperListener.init();
// Initialize our defined Connectors
synchronized (connectorsLock) {
for (Connector connector : connectors) {
// 初始化 Connectors Connector org.apache.catalina.connector
connector.init();
}
}
}
看方法最重要的地方:
- // 初始化
engine.init(); 对应的是 StandardEngin- // Executor 初始化 对应的是 StandardThreadExecutor
executor.init();- connector.init();
StandardService类的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {
LogPropertiesTest.debug("10、StandardService : 执行 startInternal() 方法; 执行类 :"+this.getClass());
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
// Start our defined Container first
if (engine != null) {
synchronized (engine) {
LogPropertiesTest.debug("10、StandardService : 执行 Engine 的 engine.start(); 方法; 执行类 :"+this.getClass());
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
LogPropertiesTest.debug("10、StandardService : 执行 Executor的 executor.start();; 方法; 执行类 :"+this.getClass());
executor.start();
}
}
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
LogPropertiesTest.debug("10、StandardService : 执行 Connector的 connector.start(); 方法; 执行类 :"+this.getClass());
// 初始化 Connectors Connector org.apache.catalina.connector
connector.start();
}
}
}
}
- // 初始化
engine.start(); 对应的是 StandardEngin- // Executor 初始化 对应的是 StandardThreadExecutor
executor.start();- connector.start();
后面的几个类
StandardEngin
StandardHost
StandardContext
的初始化和开始方法和上面的机制都是类似此处就不再贴出源码了。
关于Connector类 与 ProtocolHandler类如何进行初始化,以及开启服务的可以看我之前写过的两篇文章
Tomcat 9 源码解析 -- Connector组件(2)
这两篇文章讲解了 Connector组件 如何作为 Service服务 与 Socket套接字 之间的桥梁。