Tomcat启动过程

Tomcat的启动是通过Bootstrap类的main方法来启动的,Bootstrap类只是入口,真正的初始化是通过Catalina类来完成的。启动的时候会将阻塞标志设置为true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public static void main(String args[]) {
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init(); // catalinaaemon
} catch (Throwable t) {
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); // 解析server.xml,初始化Catalina
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);
}
} catch (Throwable t) {
System.exit(1);
}
}

启动前首先会调用bootstrap.init()方法进行类加载器的初始化,同时初始化一个Catalina实例,把Catalina父类加载器设置为了sharedLoader类加载器,且默认catalinaLoadersharedLoader默认其实就是commonLoader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public void init() throws Exception {
// catalina.home表示安装目录
// catalina.base表示工作目录
setCatalinaHome();
setCatalinaBase();
// 初始化commonLoader、catalinaLoader、sharedLoader
// 其中catalinaLoader、sharedLoader默认其实就是commonLoader
initClassLoaders();
// 设置线程的所使用的类加载器,默认情况下就是commonLoader
Thread.currentThread().setContextClassLoader(catalinaLoader);
// 如果开启了SecurityManager,那么则要提前加载一些类
SecurityClassLoad.securityClassLoad(catalinaLoader);
// 加载Catalina类,并生成instance
if (log.isDebugEnabled())
log.debug("Loading startup class");
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();

// Set the shared extensions class loader
// 设置Catalina实例的父级类加载器为sharedLoader(默认情况下就是commonLoader)
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;
}

private void initClassLoaders() {
try {
// CommonClassLoader是一个公共的类加载器,默认加载${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar下的class
commonLoader = createClassLoader("common", null); // 虽然这个地方parent是null,实际上是appclassloader
// System.out.println("commonLoader的父类加载器===="+commonLoader.getParent());
if( commonLoader == null ) {
// no config file, default to this loader - we might be in a 'single' env.
commonLoader = this.getClass().getClassLoader();
}
// 下面这个两个类加载器默认情况下就是commonLoader
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);
} catch (Throwable t) {
System.exit(1);
}
}

首先是通过Catalinaload方法进行资源的加载和初始化,首先是通过Digester解析器server.xml配置文件进行解析,解析server.xml最主要的作用:

  • 把server.xml中定义的节点都生成对应的Java对象,如在解析某个Host节点时对应生成一个StandardHost对象
  • 把server.xml中定义的节点的层级关系解析出来,如StandardContext对象.addChild(StandardHost对象)
  • 设置每个容器的pipeline的基础Valve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public void load() {
if (loaded) {
return;
}
loaded = true;
long t1 = System.nanoTime();
// 如果catalinaHome和catalinaBase是相对路径,那么在这里会转化为绝对路径
initDirs();
initNaming();
// 初始化server.xml文件解析器
Digester digester = createStartDigester();

InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
// 先从文件系统获取server.xml
try {
file = configFile(); // 获取catalina.base目录下的conf/server.xml文件
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
} catch (Exception e) {
}
// 如果文件系统没有,则从classloader中获取server.xml
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
} catch (Exception e) {
}
}
// 如果没找到server.xml,那么则从classloader中找server-embed.xml
if( inputStream==null ) {
try {
inputStream = getClass().getClassLoader() .getResourceAsStream("server-embed.xml");
inputSource = new InputSource(getClass().getClassLoader() .getResource("server-embed.xml").toString());
} catch (Exception e) {
}
}
// 如果没找到server.xml或server-embed.xml,那么告警
// 如果文件存在,判断文件没有可读权限
if (inputStream == null || inputSource == null) {
return;
}
try {
// 解析server.xml或server-embed.xml文件
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
}
}
// 解析完server.xml或server-embed.xml后,将catalina设置到StandardServer中
getServer().setCatalina(this);
// 把System.out和System.err替换成SystemLogHandler对象
initStreams();
// 解析完配置文件,开始初始化Server,而从初始化Server开始,就包括了一系列的子组件的初始化
try {
getServer().init();
} catch (LifecycleException e) {
}
}

解析server.xml生成实例的流程及主要做的事如下所示:

  1. StandardServer server = new StandardServer();
  2. catalina.setServer(server);
  3. server.addLifecycleListener(...);
  4. StandardService service = new StandardService();
  5. server.addService(service);
  6. Connector connector = new Connector(); // 会根据配置初始化protocolHandler
    1. endpoint = new JIoEndpoint(); // 初始化Endpoint,JioEndpoint中会setMaxConnections(0);
    2. cHandler = new Http11ConnectionHandler(this);
    3. ((JIoEndpoint) endpoint).setHandler(cHandler); // endpoint对应的连接处理器
  7. service.addConnector(connector);
  8. Engine engine = new StandardEngine(); // pipeline.setBasic(new StandardEngineValve());
  9. service.setContainer(engine);
  10. Host host = new StandardHost(); // pipeline.setBasic(new StandardHostValve());
  11. engine.addChild(host);
  12. Context context = new StandardContext(); // pipeline.setBasic(new StandardContextValve());
  13. host.addChild(context);
  14. engine.setParentClassLoader(Catalina.class.getClassLoader()); // 实际调用的是ContainerBase.setParentClassLoader方法,设置属性parentClassLoader为shareClassLoader

然后调用LifecycleBaseinit(),执行各个容器自身的状态改变而配置的事件监听器,以及各自实现的initInternal()初始化方法。Tomcat初始化主要做了以下事情:

  • StandardServer实例注册到JMX
  • StringCache实例注册到JMX
  • StandardService实例注册到JMX
  • container.init(); // 对StandardEngine进行初始化
    • 初始化startStopExecutor线程池,用来启动子容器的
  • connector.init(); // 对Connector进行初始化
    • adapter = new CoyoteAdapter(this);
    • protocolHandler.setAdapter(adapter);
    • protocolHandler.init(); // 初始化协议处理器
      • endpoint.init(); // 初始化协议处理器对应的endpoint,默认在初始化的时候就会bind
      • endpoint.bind()
        • serverSocketFactory = new DefaultServerSocketFactory(this);
        • serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress());
    • mapperListener.init();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// getServer().init()实际调用的是StandardServer的initInternal()
public final class StandardServer extends LifecycleMBeanBase implements Server {
protected void initInternal() throws LifecycleException {
super.initInternal(); // 将StandardServer实例注册到jmx
// 每个Server下都有一个全局的StringCache
onameStringCache = register(new StringCache(), "type=StringCache");
// MBeanFactory是JMX中用来管理Server的一个对象,通过MBeanFactory可以创建、移除Connector、Host等待
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
globalNamingResources.init();
// service初始化
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
}
// services[i].init()实际调用的是StandardService的initInternal()
public class StandardService extends LifecycleMBeanBase implements Service {
protected void initInternal() throws LifecycleException {
super.initInternal(); // 将StandardService注册到jmx中
// 将Service下的容器进行初始化,默认情况下是StandardEngine
if (container != null) {
container.init(); // 注意:这里是Engine,这个流程只会初始化StandardEngine,并没有去初始话Engine下的Host,那么Host是在哪初始化的呢?
// 实际上,对于Host容器,并不需要进行初始化
}
// 初始化线程池,可以在Service下配置定义executor,默认实现类为org.apache.catalina.core.StandardThreadExecutor
// 这个初始化只是走了一下生命周期的初始化流程,没有其他作用
for (Executor executor : findExecutors()) {
if (executor instanceof LifecycleMBeanBase) {
((LifecycleMBeanBase) executor).setDomain(getDomain());
}
executor.init();
}
// 初始化连接器,为什么这里要同步,而上面的container和executor不同步?
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
connector.init();
} catch (Exception e) {}
}
}
}
}
// container.init()实际调用的是StandardEngine的initInternal()
public class StandardEngine extends ContainerBase implements Engine {
protected void initInternal() throws LifecycleException {
// Realm,域对象,用来存储用户、密码、权限等的数据对象,它的存储方式可以是内存、xml、数据库等待,主要作用是配合Tomcat实现资源认证。
getRealm();
super.initInternal(); // Engine是容器,所以这里会调用ContainerBase的initInternal方法。
}
}
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
protected void initInternal() throws LifecycleException {
BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<Runnable>();
// 开启、停止容器的线程池
startStopExecutor = new ThreadPoolExecutor(getStartStopThreadsInternal(),getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,startStopQueue,new StartStopThreadFactory(getName() + "-startStop-"));
startStopExecutor.allowCoreThreadTimeOut(true);
super.initInternal(); // 将容器注册到jmx中
}
}
// connector.init()实际调用的是Connector的initInternal()
public class Connector extends LifecycleMBeanBase {
protected void initInternal() throws LifecycleException {
super.initInternal();
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
if (null == parseBodyMethodsSet) {
setParseBodyMethods(getParseBodyMethods());
}
if (protocolHandler.isAprRequired() &&!AprLifecycleListener.isAprAvailable()) {
throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoApr", getProtocolHandlerClassName()));
}
try {
protocolHandler.init();
} catch (Exception e) {}
mapperListener.init();
}
}
// protocolHandler.init()实际调用的是AbstractProtocol的init(),然后在调用具体的endpoint.init()
public abstract class AbstractProtocol<S> implements ProtocolHandler, MBeanRegistration {
public void init() throws Exception {
if (oname == null) {
oname = createObjectName();
if (oname != null) {
Registry.getRegistry(null, null).registerComponent(this, oname, null);
}
}
if (this.domain != null) {
try {
tpOname = new ObjectName(domain + ":" + "type=ThreadPool,name=" + getName());
Registry.getRegistry(null, null).registerComponent(endpoint, tpOname, null);
} catch (Exception e) {
getLog().error(sm.getString("abstractProtocolHandler.mbeanRegistrationFailed", tpOname, getName()), e);
}
rgOname=new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
Registry.getRegistry(null, null).registerComponent(getHandler().getGlobal(), rgOname, null );
}
String endpointName = getName();
endpoint.setName(endpointName.substring(1, endpointName.length()-1));
try {
endpoint.init();
} catch (Exception ex) {
throw ex;
}
}
}

容器的启动

启动容器主要是部署应用,部署应用分为两部分:部署server.xml中定义的Context,部署webapp文件夹下的Context。部署一个应用主要分为以下步骤:

  • 生成Context对象,server.xml中定义的Context在解析server.xml时就已经生成了,webapp文件夹下的是在部署之前生成的
  • 为每个应用生成一个WebappClassLoader
  • 解析web.xml
  • 设置Context对象中的属性,比如有哪些Wrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
public class Catalina {
public void start() {
if (getServer() == null) load();
if (getServer() == null) return;
try {
getServer().start(); //
} catch (LifecycleException e) {
try {
getServer().destroy();
}
return;
}
// Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(false);
}
}

// 是否需要阻塞,await标记是在通过Bootstrap类启动时设置为true的
if (await) { // true
await(); // 使用ServerSocket来监听shutdown命令来阻塞
stop(); // 如果阻塞被解开,那么开始停止流程
}
}
public void await() {
getServer().await();
}
}

public final class StandardServer extends LifecycleMBeanBase implements Server {
public void await() {
if( port == -2 ) {
return;
}
if( port==-1 ) {
try {
awaitThread = Thread.currentThread();
while(!stopAwait) {
try {
Thread.sleep( 10000 );
}
}
} finally {
awaitThread = null;
}
return;
}
try {
awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address));
} catch (IOException e) {
return;
}
try {
awaitThread = Thread.currentThread();
while (!stopAwait) {
ServerSocket serverSocket = awaitSocket;
if (serverSocket == null) {
break;
}
Socket socket = null;
StringBuilder command = new StringBuilder();
try {
InputStream stream;
long acceptStartTime = System.currentTimeMillis();
try {
socket = serverSocket.accept();
socket.setSoTimeout(10 * 1000); // Ten seconds
stream = socket.getInputStream();
} catch (SocketTimeoutException ste) {
continue;
} catch (AccessControlException ace) {
continue;
} catch (IOException e) {
if (stopAwait) break;
break;
}
int expected = 1024; // Cut off to avoid DoS attack
while (expected < shutdown.length()) {
if (random == null) random = new Random();
expected += (random.nextInt() % 1024);
}
while (expected > 0) {
int ch = -1;
try {
ch = stream.read();
} catch (IOException e) {
ch = -1;
}
if (ch < 32 || ch == 127) {
break;
}
command.append((char) ch);
expected--;
}
} finally {
try {
if (socket != null) socket.close();
}
}
boolean match = command.toString().equals(shutdown);
if (match) {
break;
}
}
} finally {
ServerSocket serverSocket = awaitSocket;
awaitThread = null;
awaitSocket = null;
if (serverSocket != null) {
try {
serverSocket.close();
}
}
}
}
}

容器的启动跟容器的初始化类似,是调用LifecycleBasestart(),执行各个容器自身的状态改变而配置的事件监听器,以及各自实现的startInternal初始化方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// getServer().start()实际调用的是StandardServer的startInternal()
public final class StandardServer extends LifecycleMBeanBase implements Server {
protected void startInternal()() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
}
// services[i].start()实际调用的是StandardServer的startInternal()
public class StandardService extends LifecycleMBeanBase implements Service {
protected void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
if (container != null) {
synchronized (container) {
container.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
}
}
}
// container.start()实际调用的是StandardEngine的startInternal()
public class StandardEngine extends ContainerBase implements Engine {
protected synchronized void startInternal() throws LifecycleException {
// 调用ContainerBase的startInternal,以异步的方式启动子容器
super.startInternal();
}
}
public abstract class ContainerBase extends LifecycleMBeanBase implements Container {
protected synchronized void startInternal() throws LifecycleException {
// 启动下级组件,如果有的话,容器的类加载器
Loader loader = getLoaderInternal();
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
Manager manager = getManagerInternal();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
Cluster cluster = getClusterInternal();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
DirContext resources = getResourcesInternal();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// 如果在server.xml中配置了<Context/>节点,那么对于Host节点就存在children,这个时候就会启动context, 并且是通过异步启动的
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
for (Future<Void> result : results) {
try {
result.get();
}
}
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
// 这个时候会触发START_EVENT事件,会进行deployApps
setState(LifecycleState.STARTING);
// Engine容器启动一个background线程
threadStart();
}
}
public class StandardHost extends ContainerBase implements Host {
protected synchronized void startInternal() throws LifecycleException {
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
Valve valve = (Valve) Class.forName(errorValve).getDeclaredConstructor().newInstance();
getPipeline().addValve(valve);
}
}
}
super.startInternal();
}
}
public class StandardContext extends ContainerBase implements Context, NotificationEmitter {
protected synchronized void startInternal() throws LifecycleException {
setConfigured(false);
if (namingResources != null) {
namingResources.start();
}
if (webappResources == null) { // (1) Required by Loader
try {
// 设置Context的资源,赋值webappResources属性,docBase地址
String docBase = getDocBase();
if (docBase == null) {
setResources(new EmptyDirContext());
} else if (docBase.endsWith(".war") && !(new File(getBasePath())).isDirectory()) {
setResources(new WARDirContext());
} else {
setResources(new FileDirContext());
}
}
}
// 如果在Context节点下配置了Loader节点,那么就会在解析配置文件的时候就会初始化Loader,比如:
// <Context path="/ServletDemo" docBase="C:\Users\IdeaProjects\ServletDemo\target\ServletDemo" addWebinfClassesResources="true"><Loader/></Context>
// 如果没有配,则生成一个WebappLoader
if (getLoader() == null) {
// Webapp类加载器的父类加载器为Host的ParentClassLoader,最终就是Catalina类的类加载器,其实就是CommonClassLoader
WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
webappLoader.setDelegate(getDelegate());
setLoader(webappLoader);
}
getCharsetMapper();
// 创建work目录,比如work\Catalina\localhost\ServletDemo
postWorkDirectory();
// Reading the "catalina.useNaming" environment variable
String useNamingProperty = System.getProperty("catalina.useNaming");
if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) {
useNaming = false;
}
if (ok && isUseNaming()) {
if (getNamingContextListener() == null) {
NamingContextListener ncl = new NamingContextListener();
ncl.setName(getNamingContextName());
ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
addLifecycleListener(ncl);
setNamingContextListener(ncl);
}
}
// 将当前线程的类加载器设置为WebClassLoader,记录一下当前线程的classloader
ClassLoader oldCCL = bindThread();
try {
if (ok) {
Loader loader = getLoaderInternal(); // 获取Context的类加载器
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start(); // 启动类加载器,包括初始话DirContext
unbindThread(oldCCL);
oldCCL = bindThread();
Cluster cluster = getClusterInternal();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
DirContext resources = getResourcesInternal();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// 这里会发布一个CONFIGURE_START_EVENT事件,虽然是事件,但其实并不是异步,ContextConfig会接收到此事件
fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); // web.xml
// Context下是Wrapper,这些Wrapper是什么时候添加进Context中的?就是上面的CONFIGURE_START_EVENT事件触发的
// 如果Wrapper不可用就启动,默认情况下是已经启动了的。
for (Container child : findChildren()) {
if (!child.getState().isAvailable()) {
child.start();
}
}
// 启动pipeline
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
}

} finally {
unbindThread(oldCCL);
}
mapper.setContext(getPath(), welcomeFiles, getResources());
try {
if (ok) {
getServletContext().setAttribute(JarScanner.class.getName(), getJarScanner());
}
mergeParameters();
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(), getServletContext());
} catch (ServletException e) {
break;
}
}
try {
Manager manager = getManagerInternal();
if ((manager != null) && (manager instanceof Lifecycle)) {
((Lifecycle) getManager()).start();
}
} catch(Exception e) {
ok = false;
}
super.threadStart();
}
if (getLoader() instanceof WebappLoader) {
((WebappLoader) getLoader()).closeJARs(true);
}
}
}
// connector.start()实际调用的是Connector的startInternal():启动Endpoint开始接收请求,构造Mapper对象,用来处理请求时,快速解析出当前请求对应哪个Context哪个Wrapper
public class Connector extends LifecycleMBeanBase {
protected void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
try {
protocolHandler.start();
}
mapperListener.start();
}
}
// protocolHandler.start()实际调用的是AbstractProtocol的start()
public abstract class AbstractProtocol<S> implements ProtocolHandler, MBeanRegistration {
public void start() throws Exception {
try {
endpoint.start();
}
}
}
// mapperListener.start()实际调用的是MapperListener的startInternal()
public class MapperListener extends LifecycleMBeanBase implements ContainerListener, LifecycleListener {
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
findDefaultHost();

Engine engine = (Engine) connector.getService().getContainer();
addListeners(engine);

Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
registerHost(host); // 将每个host注册到Mapper.hosts中
}
}
}
}
  1. catalina.start()
  2. getServer().start()
    1. fireLifecycleEvent(CONFIGURE_START_EVENT, null)
    2. services[i].start()
      1. container.start(); // 启动StandardEngine
        1. results.add(startStopExecutor.submit(new StartChild(children[i]))); // 每个Childrean容器StandardHost用单独的线程启动
          1. results.add(startStopExecutor.submit(new StartChild(children[i]))); // 每个Childrean容器StandardContext用单独的线程启动,以下为一个应用的启动过程
            1. 生成一个WebappLoader
            2. 启动WebappLoader
              1. 生成WebappClassLoader
              2. /WEB-INF/classes/WEB-INF/lib目录作为loaderRepositories,后面应用如果加载类就从这两个目录加载
            3. fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
              1. 解析web.xml文件
                1. 创建WebXml对象
                2. 解析web.xml文件内容设置WebXml对象属性
                  1. WebXML对象有以下几个主要属性
                    1. Map<String,ServletDef> servlets
                    2. Map<String,String> servletMappings
                    3. Map<String,FilterDef> filters
                    4. Set<FilterMap> filterMaps
                3. 收集ServletContainerInitializers
                4. 将WebXML对象中的信息配置到Context对象中
                  1. context.addFilterDef(filter);
                  2. context.addFilterMap(filterMap);
                  3. context.addApplicationListener(listener);
                  4. 遍历每个ServletDef,生成一个Wrappercontext.addChild(wrapper);
            4. 调用ServletContainerInitializers
          2. 上面会启动在server.xml中定义的Context,接下来会启动webapp文件夹下面的Context,是通过HostConfig触发的,调用HostConfigstart()
            1. deployApps();
              1. deployDescriptors(configBase, configBase.list()); // 描述符部署
              2. deployWARs(appBase, filteredAppPaths); // war包部署
              3. deployDirectories(appBase, filteredAppPaths); // 文件夹部署
                1. 生成Context对象
                2. context.setName(cn.getName());
                3. context.setPath(cn.getPath());
                4. host.addChild(context); // 这里会启动context,启动Context就会执行和上面类似的步骤
        2. threadStart(); // 启动一个background线程
      2. executor.start(); // 启动线程池, 如果用的默认连接池,这里不会启动
      3. connector.start(); // 启动请求连接器
        1. protocolHandler.start(); // 启动接收连接
          1. endpoint.start(); // 启动Endpoint
            1. 如果没有配置Executor,就创建一个默认的Executor
            2. 初始化connectionLimitLatch
            3. 如果是NIO,则运行Poller线程
            4. 运行Acceptor线程
        2. mapperListener.start();
          1. 主要初始化Mapper对象,Mapper对象的结构层级如下
            1. Mapper中有属性Host[] hosts
            2. Host中有属性ContextList contextList
            3. ContextList中有属性Context[] contexts
            4. Context中有属性ContextVersion[] versions
            5. ContextVersion中有如下属性
              1. Wrapper[] exactWrappers,保存需要根据Servlet名字精确匹配的Wrapper
              2. Wrapper[] wildcardWrappers,保存需要根据Servlet名字匹配以(“/*”)结尾的Wrapper
              3. Wrapper[] extensionWrappers,保存需要根据Servlet名字匹配以(“*.”)开始的Wrapper
              4. Wrapper中有如下两个属性
                1. name,Wrapper的名字
                2. object,真实的Wrapper的对象
  3. catalina.await(); // 使用ServerSocket来监听shutdown命令来阻塞
  4. catalina.stop(); // 如果阻塞被解开,那么开始停止流程