tomcat 启动

启动流程

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
- Bootstrap.main()
- Bootstrap bootstrap = new Bootstrap(); 实例化Bootstrap实例
- bootstrap.init(); 1.设置catalinaHome和catalinaBase 2.初始化类加载器,实例化**ClassLoaders
- setCatalinaHome(); 设置Catalina path,System.getProperty("catalina.home"),值为tomcat根目录
- setCatalinaBase(); 值为D:\workspace-e3\.metadata\.plugins\org.eclipse.wst.server.core\tmp2
- initClassLoaders(); 实例化**ClassLoaders,创建URLClassLoader
- 初始化classloader,第二个参数为父classLoader commonLoader = createClassLoader("common", null); catalinaLoader = createClassLoader("server", commonLoader); sharedLoader = createClassLoader("shared", commonLoader); 最终执行结果是,创建了commonLoader,catalinaLoader 和 sharedLoader,其中 catalinaLoader 和 sharedLoader 默认均使用 父classLoader: 即 commonLoader
- bootstrap.createClassLoader()
- 读取配置文件中配置的仓库路径(需要加载的jar包的路径) CatalinaProperties.getProperty(name + ".loader");
- CatalinaProperties类中静态块中 static {loadProperties();} 后续从properties中取
- loadProperties()方法, 读取catalina.base\\conf\\catalina.properties配置文件到prop属性中 D:\workspace-e3\.metadata\.plugins\org.eclipse.wst.server.core\tmp2\conf\catalina.properties
- bootstrap.replace()将${catalina.home}等替换成具体的路径
- 根据逗号截取出每个资源路径
- URL url = new URL(repository); 先判断是不是网络资源,即先尝试使用URL加载,若它是网络资源则能加载成功, 否则捕获异常接着下面使用本地加载
- 本地加载.根据路径结尾以*.jar,.jar或路径,创建不同类型的repository对象
- RepositoryType枚举类分类
- DIR,// 表示整个目录下的资源,包括所有Class,Jar包以及其他类型资源
- GLOB,// 表示整个目录下所有的Jar包资源,仅仅是.jar后缀的资源
- JAR,// 表示单个Jar包资源
- URL// 表示从URL上获取的Jar包资源
- 根据以上的repository列表创建classLoader. ClassLoaderFactory.createClassLoader(repositories, parent)
- 遍历repositories,判断repositoryType.目的是将每种资源转换为new URL(),并添加到URL[]数组中
0.若是RepositoryType.URL类型的资源,直接new一个URL实例即可
1.若是DIR类型,则根据路径创建java.net.URL对象;
2.若是GLOB(这里是E:\Java\apache-tomcat-7.0.82-01\lib),则遍历该目录下的jar包,创建文件,每个jar文件对应一个URL对象;
- 最后根据以上所有的url,创建URLClassLoader并返回.该类构造器接收一个URL[]数组类型 return new URLClassLoader(array)
- Thread.currentThread().setContextClassLoader(catalinaLoader); 为当前线程设置classLoader为catalinaLoader
- 若启用了安全管理,则会在这里加载一些所需的包(默认不启用) SecurityClassLoad.securityClassLoad(catalinaLoader);
- 使用catalinaLoader加载catalina类 Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance();
- 设置catalina对象的parentClassLoader属性为sharedLoader, 由于前面sharedLoader默认使用的是父加载器commonLoader, 所以此处相当于设置为commonLoader org.apache.catalina.startup.Catalina.setParentClassLoader(sharedLoader);
- bootstrap对象 保存catalina的引用 catalinaDaemon = startupInstance;
- 处理"start"命令
- 1.setAwait(true) 设置catalina.await=true
- 2.daemon.load(args); 加载配置资源,通过反射调用catalina.load()方法 (1)创建digester实例,digester解析conf/server.xml文件 (2)调用Server.init()级联初始化各个组件
- Catalina中 initDirs() 设置catalina.base和catalina.home和user.dir的property属性, 检查java.io.tmpdir属性是否存在
- initNaming() 设置java.naming.factory.url.pkgs和java.naming.factory.initia这两个System.setProperty
- 创建并执行digester,使用digester解析server.xml Digester digester = createStartDigester(); Digester类按照预定的规则解析server.xml,将元素转化为对象, 包括构造对象,set属性到对象字段,同时维护相互关联关系
- new Digester() 创建digester对象
- digester.addObjectCreate() 1)添加对象创建规则ObjectCreateRule 2)SetPropertiesRule 3)SetNextRule 添加StandardServer等各级容器的关系和处理规则
- 创建Server实例,默认实现类是StandardServer, 可以通过server节点的className属性指定自己的实现,一般不需要
- 设置Server属性
- 调用setServer()将Server设置到Catalina对象中.可在本Catalina类中搜索setServer()方法
- 创建JNDI实例对象,GlobalNamingResources,并设置其属性.并调用standServer.setGlobalNamingResources()方法装配到server中
- 为Server添加生命周期监听
- 创建service实例,创建完成后,通过addService()添加到server中
- 为server添加生命周期监听器.默认未指定监听器,347行的null
- 为service添加Executor
- 为service添加Connector
- 设置属性时,将executor属性排除在外.因为Connector创建时,即ConnectorCreateRule类中, 会判断当前是否指定了executor属性.若是,则从Service中查找该名称的executor并设置到Connector中.
- 为Connector添加 生命周期监听器.默认未指定
- 添加子元素解析规则.这部分指定了Servlet容器相关的各级嵌套子节点的解析规则. 且每类嵌套子节点的解析封装为一个RuleSet类(跟进去看).包括GlobalNamingResources,Engine,Context,Cluster的解析
- 使用sax读取server.xml file = configFile();
- digester.parse(inputSource); 使用digester解析读取的xml,在此过程中会初始化各个组件实例及其依赖关系. 最后会把server.xml文件中的内容解析到StandardServer中 (创建standServer对象并维护对象间关系)
- configure();
- getXMLReader().parse(input);
- ......
- 经过java里SAXPaser解析InputSource后,调用Digester.startElement()
- 遍历rules rule.begin(namespaceURI, name, list); 分别创建StandardServer实例
- new StandardServer()构造器
- new NamingResources()
- new NamingContextListener() addLifecycleListener(namingContextListener);
- setPropertiesRule()
- standardService.addConnector()
- standardServer.addService() 向server中添加一个新的service. digester在xml解析时会注入这个关系
- digester解析会做很多初始化操作,以后细化...
- Connector con = new Connector(attributes.getValue("protocol")); 创建Connector,会有多个Connector,和xml中配置的数量有关
- Connector构造器
- setProtocol(protocol);
- 根据xml配置的协议类型,此处是Http11Protocol setProtocolHandlerClassName ("org.apache.coyote.http11.Http11Protocol");
- 实例化Http11Protocol
- Http11Protocol构造器
- endpoint = new JIoEndpoint();
- getServer().init(); 调用Server的init()方法,初始化各个组件. 它会调用各个service子容器的init()方法, 从而级联完成组件初始化 在调用init()时第3步,调用子类StandardService.initInternal(); 各个组件有个共同的父类: LifecycleBase,用于管理组件的生命周期和状态变化。 在走Server.init()前,先走父类LifecycleBase.init(),事件驱动当前组件状态的变化. 从StandardServer到StandardWrapper,都会调用initInternal(), 并伴随调用共有父类LifecycleBase.init()
- init()方法在父类LifecycleBase中, 调用父类LifecycleBase.init()
- super.initInternal(); 即父类LifecycleBase.initInternal()
- 1.先判断状态是否为LifecycleState.NEW(默认是)
2.LifecycleBase.setStateInternal(LifecycleState.INITIALIZING, null, false); 变更生命周期状态为LifecycleState.INITIALIZING 调用各个事件监听中的 初始化方法
- 3.initInternal();这个方法一般被子类覆盖,执行子类自己的逻辑 此处为StandServer.initInternal()
- StandServer.initInternal()中 super.initInternal(); 调用父类LifecycleMBeanBase.initInternal()
- LifecycleMBeanBase.initInternal()中 将容器托管到JMX,便于运维管理
- 遍历services调用service.init() services[i].init();
- StandardService.init()中 init()方法在父类LifecycleBase中, 调用父类LifecycleBase.init()
- LifecycleBase.init()中 setStateInternal(LifecycleState.INITIALIZING, null, false); 变更生命周期状态为LifecycleState.INITIALIZING(通过事件变更)
- initInternal();// 进入子类的initInternal()方法, 即调用StandardService.initInternal()
- StandardService.initInternal()中 container.init(); 此处container即为StandardEngine.init() StandardEngine的子容器standardContext及其子容器没有init初始化逻辑
- StandardEngine.init()中,略去LifecycleBase中生命周期变更的重复逻辑 StandardEngine.initInternal()中 getRealm(); 创建realm
- super.initInternal(); 即为ContainerBase.initInternal() Engine,Host,Context,Wrapper容器都拥有共同父类ContainerBase
- ContainerBase.initInternal()中 startStopExecutor = new ThreadPoolExecutor() 初始化startStopExecutor,用于管理启动和关闭的线程
- super.init()即LifecycleMBeanBase.initInternal()
- ......略去各个StandardHost.init()
- ...
- lifecycleBase.init()
- LifecycleBase.setStateInternal(LifecycleState.INITIALIZED, null, false);初始化完成 StandardContext父类LifecycleBase变更生命周期状态,调用各个事件监听中的 initializing
- initInternal();// 进入子类StandardContext.initInternal()方法
- super.initInternal(); StandardContext.initInternal()调用父类ContainerBase.initInternal() 它会创建startStopExecutor 并调用父类LifecycleMBeanBase.initInternal(); 这里会将容器托管到JMX
- this.addLifecycleListener(new TldConfig()); 添加TldConfig监听
- setStateInternal(LifecycleState.INITIALIZED, null, false); // 更新组件生命周期状态为LifecycleState.INITIALIZED
- ...
- contextConfig.lifecycleEvent() contextConfig AFTER_INIT_EVENT生命周期事件处理
- contextConfig.init(); context初始化阶段,context属性配置 tomcat提供的默认配置添加到context实例 完成对应的 每个web应用项目的配置解析(web.xml)
- createContextDigester()
- contextDigester.getParser();
- contextConfig(contextDigester); 解析config.xml配置 E:\Java\apache-tomcat-7.0.82-01\conf\context.xml
- createWebXmlDigester()
- beforeStart() Lifecycle.BEFORE_START_EVENT状态
- executor.init(); 初始化executors,即tomcat间可共享的线程池
- connector初始化
- connector.initInternal();
- adapter = new CoyoteAdapter(this); 构建与指定连接器关联的新CoyoteAdapter
- protocolHandler.setAdapter(adapter); 给 协议处理器 添加 adapter
- protocolHandler.init(); 初始化具体协议类型,如Http11Protocol协议
- AbstractHttp11JsseProtocol.init()
- endpoint初始化之前,需要初始化ssl实现类 sslImplementation = SSLImplementation.getInstance(sslImplementationName); return new org.apache.tomcat.util.net.jsse.JSSEImplementation();
- super.init(),即AbstractProtocol.init() 1.注册组件JIoEndPoint; 2.endpoint.init() 设置work threads的数量,默认为200,并创建serverSocket对象
- abstractProtocol.bind() 设置线程数,网络连接数
- 初始化acceptor线程数量,默认1个; 初始化最大连接数,此值为server.xml的connector元素的属性MaxThreads值,(若不设置则)默认200
- abstractEndpoint.getMaxThreadsWithExecutor() 返回成员变量maxThreads=200
- abstractEndpoint.setMaxConnections(getMaxThreadsWithExecutor()); 设置最大连接数
- initializeConnectionLatch(); 创建LimitLatch对象并初始化连接数 即 connectionLimitLatch = new LimitLatch(getMaxConnections());
- serverSocketFactory = new DefaultServerSocketFactory(this); 创建ServerSocketFactory
- serverSocket = serverSocketFactory.createSocket(getPort(),getBacklog()); 创建serverSocket
- 初始化mapper listener mapperListener.init();
- 容器初始化完毕,LifecycleBase会将容器的状态更改为初始化完毕 setStateInternal(LifecycleState.INITIALIZED, null, false);
- 3.daemon.start().即catalina.start() 运行各个组件,容器开始启动.
- getServer().start() 启动Server 即standardServer.start(),由于未重写该方法. 所以会先调用父类LifecycleBase.start()
- LifecycleBase.start()中 setStateInternal(LifecycleState.STARTING_PREP, null, false); // 启动前将状态设置为LifecycleState.STARTING_PREP
- startInternal(); // 模板方法调用子类逻辑
- StandardServer.startInternal();中 1.发布configure_start事件 fireLifecycleEvent(CONFIGURE_START_EVENT, null);
- 2.设置状态为starting setState(LifecycleState.STARTING); 3.globalNamingResources.start(); globalNamingResources.start();
- 4.services[i].start(); 启动多个Service子容器. 略去LifecycleBase.start()的重复逻辑, 调用standardService.startInternal()
- standardService.startInternal()中 container.start(): 启动container,此时container为StandardEngine
- StandardEngine.startInternal()中 调用super.startInternal(), 即ContainerBase.startInternal()
- ContainerBase.startInternal()中 若配置了loader,manager,cluster,realm等,则会启动这些下属组件. 在engine,host,context等容器的启动逻辑都会调用该父类(ContainerBase)的此方法用于加载启动子容器. containerBase.startInternal()会向线程池 提交启动子容器的任务,并阻塞等待子容器启动的返回结果判定是否启动成功
- ContainerBase.startInternal()中 getLoaderInternal()
- Lock readLock = loaderLock.readLock(); readLock.lock(); try { return loader; } finally { readLock.unlock(); }
- 若配置了realm组件,则启动 Realm realm = getRealmInternal(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start();
- 若有子容器,则启动 Container children[] = findChildren();
- results.add(startStopExecutor.submit(new StartChild(children[i]))); 提交启动子容器的任务,后续StandHost的操作会在新线程中完成
- StartChild.call() class StartChild implements Callable<Void> StartChild类实现Callable,会执行覆写的call()方法
- child.start(); 启动子容器,比如此处Engine的子容器就是Host 即调用standHost.start()
- StandardHost.start() 使用父类LifecycleBase中的start()方法
- LifecycleBase.start()中
- LifecycleBase.start()中 setStateInternal(LifecycleState.STARTING_PREP, null, false); 触发before_start事件,即Host容器发布before_start事件, 相关监听器会接收到通知,执行相应逻辑,如HostConfig监听器
- HostConfig.lifecycleEvent() HostConfig实现LifecycleListener接口,在StandardHost启动时生命周期发生变化时, 会调用HostConfig的lifecycleEvent()对特定事件进行逻辑处理
- 调用HostConfig.beforeStart() BEFORE_START_EVENT
- beforeStart() 会创建appBase和configBase路径所需的目录
- 判断host.getCreateDirs(),对appBase和configBase进行mkdirs()
- lifecycleBase.startInternal(); 会调用子类StandardHost.startInternal()
- StandardHost.startInternal()中 Valve[] valves = getPipeline().getValves();
- 获取错误阀的阀名,即org.apache.catalina.valves.ErrorReportValve getErrorReportValveClass()
- 若有错误阀名,尝试遍历所有阀找出这个class类 StandardPipline.getValues() 通过value.getNext()循环遍历将所有Value成数组返回
- 若没有找到,则反射创建实例,并添加到pipeline中
- super.startInternal(); 调用ContainerBase.startInternal()新起线程启动子容器(即Host的Context子容器)
- ContainerBase.startInternal()中 results.add(startStopExecutor.submit(new StartChild(children[i]))); 启动StandardContext!!!!!!后续子节点都是Context容器的操作
- 调用StandardContext.start(), 由于该类未重写start(), 所以实际上调用父类lifecycleBase.start()
- lifecycleBase.start()中 若是LifecycleState.NEW状态
- LifecycleBase.setStateInternal(LifecycleState.STARTING_PREP, null, false); 设置LifecycleState.STARTING_PREP状态,即before_start
- 调用ContextConfig.beforeStart(); // 在context启动前触发,用于更新Context的docBase属性 和 解决web目录锁的问题
- LifecycleBase.startInternal();
- 调用子类StandardContext.startInternal() 完成对web应用的初始化工作
- StandardContext.startInternal()里经过一系列操作,将状态变更为CONFIGURE_START_EVENT standardContext.fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); 发布CONFIGURE_START_EVENT事件,contextConfig监听以完成servlet创建
- contextConfig.configureStart(); web应用初始化.解析web.xml文件, 创建wrapper,Filter,ServletContextListener等.
- contextConfig.webConfig()
- webXml.configureContext(context); 解析web.xml,将webXml对象设置给context
- Lin1388 webXml.configureContext(context); 解析servlet,将Servlet包装成Wrapper
- context.createWrapper()
- wrapper.setServletClass(servlet.getServletClass()); 将wrapper与servlet绑定
- context.addChild(wrapper); 将wrapper添加到context中
- containerBase.addChildInternal(child);
- child.start(); 即standardWraper.start()
- Wrapper容器 StandardWrapper.start()
- LifecyclesetStateInternal(LifecycleState.STARTED, null, false); 设置LifecycleState.STARTED状态,即after_start
- 调用context.setDocBase(originalDocBase);
- containerBase.threadStart(); 启动Context层级的后台任务进程.Cluster后台任务(包括部署变更检测,心跳).Pipeline中Value的后台任务处理(如果有定时处理任务)
- ContainerBase.startInternal()中 setState(LifecycleState.STARTING); 设置容器状态为STARTING,此时会触发START_EVENT生命周期事件.即start事件
- 调用HostConfig.start(); Host启动时触发,完成服务器启动过程中的 Web应用部署. 需要 Host的deployOnstartup="true"才会在服务器启动时部署web应用.
- 若有管道,则启动 if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();
- executor.start(); 启动service容器的多个线程池executors
- connector.start(); 启动service组件的多个connector
- connector.startInternal()
- protocolHandler.start(); 启动 协议处理器
- endpoint.start();
- createExecutor(); 创建endpoint私有的线程池,即ThreadPoolExecutor线程池
- abstractEndpoint.createExecutor()
- new TaskQueue(); 用来运行线程池执行器的任务队列,该类extends LinkedBlockingQueue<Runnable> new TaskThreadFactory() implements ThreadFactory 线程工厂,用于创建并返回线程 executor = new ThreadPoolExecutor() 根据前两者 创建线程池
- initializeConnectionLatch(); 创建LimitLatch对象,之前init时已经创建.此处直接返回
- startAcceptorThreads(); 创建多个Acceptors
- getAcceptorThreadCount(); 获取acceptor线程数量,默认1
- return new JIoEndpoint.Acceptor() implements Runnable; 创建JIoEndpoint
- Thread t = new Thread(acceptors[i], threadName); 根据JIoEndpoint创建线程,且是守护线程
- mapperListener.start(); 启动 mapperListener
- findDefaultHost(); 从engine中获取defaultHost并设置给mapper
- 从engine中获取defaultHost并设置给mapper mapper.setDefaultHostName(defaultHost);
- addListeners(engine);
- container.addContainerListener(this); container.addLifecycleListener(this); addListeners(child); 其中this为engine,child为host.即给engine注册监听
- registHost() 向mapper注册host及其下的context,wrapper
- mapper.addHost(host.getName(), aliases, host);
- registerContext((Context) container); 向mapper注册context
- prepareWrapperMappingInfo(context, (Wrapper) container, wrappers);

bootstrap.init()

创建 commonClassLoader,和 两个子 类加载器 catalinaLoader 和 sharedLoader,当然都是 URLClassLoader 实例,加载 一些 Jar.

设置当前线程的上下文类加载器为 catalinaLoader

设置 Catalina 的 父类加载器为 sharedLoader

处理 start 命令

分为 load 和 start 两步

load

读取 conf/server.xml 配置,使用 digester 解析,组装对象.

server.init() 主要遍历 services,调用其 init() 方法
状态变更: LifecycleState.NEW -> LifecycleState.INITIALIZING -> initInternal() -> LifecycleState.INITIALIZED

service.init()
调用 engine.init(),初始化executor,遍历初始化 connectors

Connector.init()
创建 CoyoteAdapter
protocolHandler 关联 adapter
protocolHandler.init(),这里面会初始化 endpoint
mapperListener.init()

StandEngine.init()
engine,host,context,wrapper 都继承自 ContainerBase,ContainerBase里会起 startStopExecutor 线程池,这个线程池用于子容器启动,父容器会等待子容器启动完成.

start

Catalina.start()
调用 server.start()

StandardServer.start()
触发 CONFIGURE_START_EVENT 事件,设置自身的状态为 STARTING,遍历调用 services.start()

StandService.start()
设置状态为 STARTING,调用 engine.start(),excutors.start(),connector.start()

StandEngine.start()
会走父类 ContainerBase.startInternal(),在 ContainerBase 中,若配了 loader,manager, cluster, realm 则 启动.
然后就查找所有子容器,每个子容器都交由 startStopExecutor 线程池 执行 StartChild 的逻辑,调用 child.start().并通过 future.get() 阻塞等待所有子容器启动成功.
pipeline.start()
设置线程状态为 STARTING,触发 START_EVENT 生命周期事件.
启动一个 ContainerBackgroundProcessor 后台线程.

ContainerBase.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
@Override
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any.启动下属组件
Loader loader = getLoaderInternal();
if ((loader != null) && (loader instanceof Lifecycle))// 若配置了loader则启动
((Lifecycle) loader).start();
logger = null;
getLogger();
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))// 若配置了安全组件Realm,则启动
((Lifecycle) realm).start();
DirContext resources = getResourcesInternal();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();

// Start our child containers, if any.启动子容器,如果有的话.
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]))); // 子容器使用 startStopExecutor 调用新线程来启动
}

boolean fail = false;
for (Future<Void> result : results) { // 启动 多个子容器的执行结果
try {
result.get(); // 阻塞直到所有子容器启动完毕
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}

}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}

// Start the Valves in our pipeline (including the basic), if any.启动容器持有的Pipeline组件的Value.若有管道,则启动
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();

// 设置容器状态为STARTING,此时会触发START_EVENT生命周期事件.
setState(LifecycleState.STARTING);

// Start our thread. 启动该层级的后台定时任务进程(不同容器调用,则启动不同容器的后台线程).用于处理如 Cluster 后台任务(包括部署变更检测,心跳).Realm 后台任务处理.Pipeline 中 Value 的后台任务处理(如果有定时处理任务)
threadStart();

}

StandardHost.startInternal()
不存在errorValve则创建,调用 ContainerBase.startInternal() 启动子容器.子容器是在 HostConfig.deployXxx里通过host.addChild(context)添加进来的.

StandContext.startInternal()
创建 WebappLoader 并启动
触发 CONFIGURE_START_EVENT 事件,contextConfig 监听以完成 servlet 创建
遍历启动子容器
启动pipline
触发listener的各种事件
初始化filter
初始化servlets,调用 load-on-startup 的 servlet 的 init() 方法
遍历 wraper,调用 wrapper.load() 加载 wrapper

StandWrapper.startInternal()
没什么重要逻辑