1.Bootstrap.main()
main方法中主要由三件事:
- BootStrap对象初始化:bootstrap.init()方法初始化bootastrap对象的三个类加载器、通过反射构造Catalina对象并赋值给bootstrap对象的catalinaDaemon属性、通过反射给Catalina对象设置parentClassLoader(注意bootstrap对象的sharedLoader和Catalina对象的parentClassLoader使用的是同一个ClassLoader)
- daemon.load(args):设置一些启动参数 3.daemon.start():调用Catalina对象的start方法
public static void main(String args[]) {
synchronized (daemonLock) {
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
...
}
daemon = bootstrap;
} else {
...
}
}
try {
String command = "start";
if (args.length > 0) {
...
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
...
} else {
log.warn("Bootstrap: command "" + command + "" does not exist.");
}
} catch (Throwable t) {
...
}
}
public void start() throws Exception {
if (catalinaDaemon == null) {
init();
}
// 在前面的初始化方法中我们知道catalinaDaemon设置的属性是Catalina类型的对象(通过反射生成的对象)
Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
method.invoke(catalinaDaemon, (Object [])null);
}
2.Catalina.start()
在Catalina中start方法又是一系列的准备,然后调用了一个getServer().start()方法。getServer()方法返回的就是当前对象的server属性(实际上Tomcat的最顶级容器就是Server)
public void start() {
if (getServer() == null) {
//如果getServer为空,则调用load方法,设置当前对象的的server属性的值
//实际上在Bootstrap的laod方法中就通过反射调用课Catalina的load方法,所以正常情况下这个getServer()不会返回空值
load();
}
if (getServer() == null) {...}
long t1 = System.nanoTime();
try {
//关键代码是这一行
getServer().start();
} catch (LifecycleException e) {
try {
getServer().destroy();
} catch (LifecycleException e1) {...}
return;
}
...
}
稍微看一下load方法:
public void load() {
if (loaded) {return;}
loaded = true;
long t1 = System.nanoTime();
initDirs();
// 在执行一些Digester之前的一些准备动作
initNaming();
// 创建和配置我们将用于启动的 Digester(一个XML解析器)
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
//接下来一系列动作就是获取inputSource inputStream,实际上就是读取启动配置文件conf/server.xml
...
try {
inputSource.setByteStream(inputStream);
// 将当前对象this推入到栈顶(即解析结果中此Catalina对象为根节点)
digester.push(this);
//解析指定输入源的内容,这里是根据conf/server.xml配置文件中的动态参数解析
digester.parse(inputSource);
} catch (SAXParseException spe) {...}
} finally {...}
// 将当前Catalina对象(this)设置给Server(实际上Server是一个接口,实现类是org.apache.catalina.core.StandardServer)
getServer().setCatalina(this);
// 设置Catalina的home和base(这两个File的默认路径就是Tomact文件夹的绝对路径)
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
initStreams();
// Start the new server
try {
// 启动Server,这里getServer()返回值实际上是:org.apache.catalina.core.StandardServer
// 参见org.apache.catalina.startup.Catalina的createStartDigester方法
getServer().init();
} catch (LifecycleException e) {...}
...
}
简单看一下createStartDigester方法
protected Digester createStartDigester() {
...
// 设置Server
// addObjectCreate 为指定参数添加“对象创建”规则。就是创建一个指定类型的server对象
digester.addObjectCreate("Server", // 对应server.xml 的 <Server>节点
"org.apache.catalina.core.StandardServer",// 属性实际类型为:org.apache.catalina.core.StandardServer
"className");
// 为指定参数添加“设置属性”规则。
digester.addSetProperties("Server");
// 为指定参数添加“设置下一个”规则。
digester.addSetNext("Server",
"setServer", // 调用setServer方法,设置属性,实际执行解析时是调用的catalina.serServer(),为什么是catalina ?因为在代码中parse之前先执行了digester.push(this)即将catalina对象作为根节点
//属性抽象类型为org.apache.catalina.Server接口,StandardServer实现了Server接口
"org.apache.catalina.Server");
digester.addObjectCreate("Server/Service", // 对应server.xml 的 <Server> -> <Service>节点
"org.apache.catalina.core.StandardService",// 属性实际类型为:org.apache.catalina.core.StandardService
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
"addService", // 这里调用的是StandardServer的addService方法,因为上一节点是Server
// 属性抽象类型为org.apache.catalina.Service,StandardService实现了Service接口
"org.apache.catalina.Service");
...
return digester;
}
通过上述分析:发现Catalina.start()调用了getServer().start(), getServer返回的实际是StandardServer类型的对象(在load方法中实例化Catalina时设置的Server属性),代码跟进: getServer().start() -> Lifecycle.start() ->LifecycleBase.start() -> startInternal() -> StandardServer.startInternal()
以上是StandardServer的UML图
3.LifecycleBase.start()
LifecycleBase是一个抽象类,start方法是一个模板方法
public final synchronized void start() throws LifecycleException {
...
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
// 这里调用自身的 startInternal方法
startInternal();
...
} catch (Throwable t) {
...
}
}
4.StandardServer.startInternal()
在一个Tomcat中可以有多个Service,在StandardServer中启动时会遍历所有的Service一个一个启动。
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (Service service : services) {
service.start();
}
}
}
5.StandardService.startInternal()
StandardService的启动中主要有四个方法:
- engine.start();
- executor.start();
- mapperListener.start(); 这一步不怎么清楚,有熟悉的帮忙指点一下?
- connector.start();
protected void startInternal() throws LifecycleException {
...
// 首先启动自定义的容器:engine的定义在server.xml中
if (engine != null) {
synchronized (engine) {
// 启动Engine容器
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
// ????
mapperListener.start();
// 第二启动自定义的连接器:connector的定义在server.xml中有单独定义
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
// 启动连机器
connector.start();
}
} catch (Exception e) {
...
}
}
}
}
6.StandardEngine.startInternal()
Engine容器用于处理由连接器(connector)处理好的Request和Response。 Engine容器继承ContainerBase类,并实现了Container。
protected synchronized void startInternal() throws LifecycleException {
// 标准容器启动,调用的是ContainerBase.startInternal()
super.startInternal();
}
ContainerBase.startInternal()
protected synchronized void startInternal() throws LifecycleException {
...
// Cluster启动
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
// Realm启动
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// 启动子容器,StandardEngine调用的,所以这里的子容器都是Engine下面的容器,主要就是Host容器
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (Container child : children) {
// 子容器启动另起线程,注意StartChild这个类
results.add(startStopExecutor.submit(new StartChild(child)));
}
MultiThrowable multiThrowable = null;
for (Future<Void> result : results) {
try {
// 校验线程运行结果,保证所有的子线程都执行成功
result.get();
} catch (Throwable e) {
...
}
}
...
// 启动Engine中的pipeline
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
setState(LifecycleState.STARTING);
// 启动将定期检查会话超时的后台线程
threadStart();
}
StartChild是ContainerBase的一个内部类,只有一个私有Container类型的素有属性;并且实现了Callable接口,实现了call()方法,call()方法只有一行代码,即child.start()调用子容器的start方法。
private static class StartChild implements Callable<Void> {
// Container类型的私有属性
private Container child;
// 设置属性值
public StartChild(Container child) {
this.child = child;
}
@Override
public Void call() throws LifecycleException {
// 调用子容器的strat方法
child.start();
return null;
}
}
继续往下走,我们发现 Engine的容器时Host,实现类是StandardHost
StandardHost的startInternal()方法中有这样一行代码:super.startInternal() 即又去调用ContainerBase.startInternal(), 继续找子容器,调用使用线程池调用子容器的启动方法。
调用链: StandardEngine.startInternal() -> ContainerBase.startInternal() -> StandardHost.startInternal() -> ContainerBase.startInternal() -> StandardContext.startInternal() -> ContainerBase.startInternal() ->
StandardWrapper.startInternal() -> ContainerBase.startInternal() 直至到Wrapper再没有子容器,则Engine启动完毕。
7.StandardThreadExecutor.startInternal()
protected void startInternal() throws LifecycleException {
taskqueue = new TaskQueue(maxQueueSize);
TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);
executor.setThreadRenewalDelay(threadRenewalDelay);
if (prestartminSpareThreads) {
executor.prestartAllCoreThreads();
}
taskqueue.setParent(executor);
setState(LifecycleState.STARTING);
}
8.MapperListener.startInternal()
- addListeners(engine)
- registerHost(host)
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
// 得到 engine 容器
Engine engine = service.getContainer();
if (engine == null) {
return;
}
// 找到默认主机
findDefaultHost();
// 给engine下的子容器一级一级添加MapperListener对象
addListeners(engine);
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
// 注册主机将注册上下文和包装器
registerHost(host);
}
}
}
递归执行,对每一个子容器添加MapperListener对象,MapperListener主要由两个变量: // 关联的映射器 host private final Mapper mapper; // 关联的Service (当前StandardService) private final Service service;
private void addListeners(Container container) {
container.addContainerListener(this);
container.addLifecycleListener(this);
for (Container child : container.findChildren()) {
addListeners(child);
}
}
9.Connector.startInternal()
Connector处理请求是主要的组件是protocolHandler,在Connector初始化的过程时通过解析conf/server.xml中的Connector标签,并设置protocolHandler属性。
先看一下Connector的构造方法:
public Connector(String protocol) {
// 调用了一个私有方法
setProtocol(protocol);
// 初始化 ProtocolHandler
ProtocolHandler p = null;
try {
// 使用全类名 (protocolHandlerClassName )反射生成对象
Class<?> clazz = Class.forName(protocolHandlerClassName);
p = (ProtocolHandler) clazz.getConstructor().newInstance();
} catch (Exception e) {
...
} finally {
this.protocolHandler = p;
}
..
}
再看一下setProtocol(protocol)方法:
public void setProtocol(String protocol) {
boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
AprLifecycleListener.getUseAprConnector();
// 当配置文件中 protocol 为 "HTTP/1.1"时,如果不做修改,最终 protocolHandlerClassName的值为 "org.apache.coyote.http11.Http11NioProtocol"
if ("HTTP/1.1".equals(protocol) || protocol == null) {
if (aprConnector) {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
} else {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
}
} else if ("AJP/1.3".equals(protocol)) {
if (aprConnector) {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
} else {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
}
} else {
setProtocolHandlerClassName(protocol);
}
}
从上面Connector的构造过程知道protocolHandler的实现类是:Http11NioProtocol
protected void startInternal() throws LifecycleException {
...
try {
// 启动 protocol
protocolHandler.start();
} catch (Exception e) {
...
}
}
ProtocolHandler是一个接口,start()方法有两个类实现了:AbstractProtocol、AbstractAjpProtocol
从上图UML图中知道,Http11NioProtocol继承自AbstractProtocol,所以 protocolHandler.start()会调用AbstractProtocol的start()方法。
10.AbstractProtocol.start()
先看一下AbstractProtocol的代码结构:
public void start() throws Exception {
...
// 启动EndPoint
endpoint.start();
// 启动超时线程
asyncTimeout = new AsyncTimeout();
Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
int priority = endpoint.getThreadPriority();
if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
priority = Thread.NORM_PRIORITY;
}
timeoutThread.setPriority(priority);
timeoutThread.setDaemon(true);
timeoutThread.start();
}
AbstractEndpoint.start()
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {
bindWithCleanup();
bindState = BindState.BOUND_ON_START;
}
// 调用内部的抽象方法,方法由子类实现,即:NioEndpoint.startInternal()
startInternal();
}
11.NioEndpoint.startInternal()
public void startInternal() throws Exception {
if (!running) {
...
// 启动Poller线程,后台一直运行着,后续用来处理HTTP请求的socket
poller = new Poller();
Thread pollerThread = new Thread(poller, getName() + "-Poller");
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
// 启动Acceptor线程,后台一直运行着,后续用来接收HTTP请求的socket
startAcceptorThread();
}
}
至此EndPoint启动完毕后Connector启动也就完成了,一个Service启动完成了,如果有多个service,则所有的Service启动都走相同的流程。当所有的Service都启动完了,Server也就启动完成。此时整个Tomcat启动完毕。