Tomcat的组织架构及启动原理

Tomca组件结构

tomcat.png

connector:主要负责接受浏览器发送过来的tcp连接请求,创建一个request和response

container:接受request和response,并开启线程处理请求封装结果

service:结合connector和container,对外提供接口服务,一个service可以有多个connector(多种连接协议)和一个container(engine,可以理解为servlet容器)

server:为service提供生存环境,负责他的生命周期,它可以包含多个service服务

Tomcat容器结构

Tomcat.png

Engine:servlect的顶层容器,包含一个或多个Host子容器;
Host:虚拟主机,负责web应用的部署和context的创建
Context:web应用上下文,包含多个wrapper,负责web配置的解析、管理所有的web资源
Wrapper:最底层的容器,是对servlet的封装,负责servlet实例的创建、执行、销毁

Tomcat启动过程

Tomcat启动时,执行启动脚本startup.sh->catalina.sh->Bootstrap->Bootstrap.main方法

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
java复制代码    public static void main(String args[]) {
// ....
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
// 1)如果daemon是空的话,先执行init方法
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
}
// ....

// 2)不同命令会调用不同daemon的不同方法,daemon是Bootstrap
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);
// 3)若命令是start,调用Boostrap的load方法和start方法
daemon.load(args);
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);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
// ...
}

private void load(String[] arguments) throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class<?> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
// 4)此处通过反射调用,catalinaDaemon的load方法,catalinaDaemon是啥呢?
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled()) {
log.debug("Calling startup class " + method);
}
method.invoke(catalinaDaemon, param);
}

// 1.1) Boostrap的init方法会在main中先执行,由此可知catalinaDaemon就是Catalina类
public void init() throws Exception {
// ...
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
// ...
catalinaDaemon = startupInstance;
}

public void start() throws Exception {
if (catalinaDaemon == null) {
init();
}

Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
method.invoke(catalinaDaemon, (Object [])null);
}

1. Catalina.load()

所以最后Bootstrap.main()->Catalina.load(),load方法中主要做了2个事情:

  1. 创建Digester类,解析conf/server.xml文件
  2. 调用server.init()进行初始化server
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
java复制代码  protected String configFile = "conf/server.xml";  
protected File configFile() {
File file = new File(configFile);
if (!file.isAbsolute()) {
file = new File(Bootstrap.getCatalinaBase(), configFile);
}
return file;
}
public void load() {
// 1)Create and execute our Digester
Digester digester = createStartDigester();

InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
// 1.1)创建文件
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
// ...
inputSource.setByteStream(inputStream);
digester.push(this);
// 1.2) 解析文件:conf/server.xml
digester.parse(inputSource);
// ...
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// ...

// 2) Start the new server
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
// ...
}

getServer.init()->LiftcycleBase.init():

  1. 更新server的LifecycleState,并发布状态变化事件
  2. 调用StandServer.initInternal()进行server的初始化
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
java复制代码public abstract class LifecycleBase implements Lifecycle {
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
// 1) 设置状态为initalizing,并发布状态变化的事件
// LifecycleState有12种状态,每种状态都有对应的Event
setStateInternal(LifecycleState.INITIALIZING, null, false);
// 2)初始化
initInternal();
// 3)设置状态为initialized,并发布状态变化事件
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}

private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
throws LifecycleException {
// ...
// 1)设置新状态
this.state = state;
// 2)获取状态的事件并发布
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
fireLifecycleEvent(lifecycleEvent, data);
}
}
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
// 循环监听:lifecycleListeners并发布事件LifecycleEvent ??监听器有哪些?如何初始化的?
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
}

public enum LifecycleState {
NEW(false, null),
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null);

private final boolean available;
private final String lifecycleEvent;
}

image-20211106152425823.png
image-20211106154522867.png

1
2
3
4
5
6
7
java复制代码    protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize our defined Services
for (Service service : services) {
service.init();
}
}

StandServer.initInternal()->LeftcycelBase.init()->StandService.initeInternal(),standService.initernel()主要实现:

  1. 初始化engine
  2. 初始化connectors
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码    protected void initInternal() throws LifecycleException {
super.initInternal();
// 1) 初始化engine
if (engine != null) {
engine.init();
}
// ...
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
// 2)初始化connectors
connector.init();
} catch (Exception e) {
// ...
}
}
}
}

初始化engine.init()->LifecycleBase.init()->StandardEngine.initernal()

初始化connetor.init()->LiftcycleBase.init()->Connector.initernal()->ProtocolHandler.init()

2. Catalina.start()

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
java复制代码    public void start() {
// ...
long t1 = System.nanoTime();

// 1) Start the new server
try {
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;
}

// 2) Register shutdown hook
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);

// If JULI is being used, disable JULI's shutdown hook since
// shutdown hooks run in parallel and log messages may be lost
// if JULI's hook completes before the CatalinaShutdownHook()
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}

if (await) {
await();
stop();
}
}

Catalina.start()->LifecycleBase.start()->StandardServer.startIniternal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码    @Override
protected void startInternal() throws LifecycleException {
// 1)更新server状态为starting,并发布状态变更事件
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);

globalNamingResources.start();

// 2)初始化service
synchronized (servicesLock) {
for (Service service : services) {
service.start();
}
}
}

StandardServer.startIniternal()->LifecycleBase.start()->StandardService.startIniternal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码    protected void startInternal() throws LifecycleException {
// 1) Start our defined Container first
if (engine != null) {
synchronized (engine) {
engine.start();
}
}
// ...
// 2) Start our defined Connectors second
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) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}

image-20211106161442089.png

1)engine.start()->LifecycleBase.start()->engine.startInternal()->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
java复制代码  	 protected synchronized void startInternal() throws LifecycleException {
// ...
// 1)启动子容器们的任务提交到线程池中
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
for (Container child : children) {
results.add(startStopExecutor.submit(new StartChild(child)));
}

MultiThrowable multiThrowable = null;
// 2)采用异步获取结果的方式,启动容器的结果
for (Future<Void> result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}

}
// ...
// Start our thread
threadStart();
}

StandardEngine的子容器是Host,所以:ContainerBase.startInternal()->LifecycleBase.start()->发布事件->HostConfig监听此事件

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
java复制代码    public void lifecycleEvent(LifecycleEvent event) {
// ...
if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
check();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.START_EVENT)) {
// 调用这个方法
start();
} else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
stop();
}
}

public void start() {
// 发布项目
if (host.getDeployOnStartup()) {
deployApps();
}
}

protected void deployApps() {
File appBase = host.getAppBaseFile();
File configBase = host.getConfigBaseFile();
String[] filteredAppPaths = filterAppPaths(appBase.list());
// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
// 发布war包项目
deployWARs(appBase, filteredAppPaths);
// Deploy expanded folders
deployDirectories(appBase, filteredAppPaths);
}

protected void deployWARs(File appBase, String[] files) {
// ...
for (String file : files) {
// ...
File war = new File(appBase, file);
if (file.toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() && !invalidWars.contains(file)) {
ContextName cn = new ContextName(file, true);
if (tryAddServiced(cn.getName())) {
try {
// ...
// 发布war的任务提交到线程池中
results.add(es.submit(new DeployWar(this, cn, war)));
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
removeServiced(cn.getName());
throw t;
}
}
}
}
// 异步获取发布结果
for (Future<?> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("hostConfig.deployWar.threaded.error"), e);
}
}
}

private static class DeployWar implements Runnable {
// ...
@Override
public void run() {
// 发布单个war
config.deployWAR(cn, war);
}
}

protected void deployWAR(ContextName cn, File war) {
// ...
Context context = null;
boolean deployThisXML = isDeployThisXML(war, cn);
try {
// ...
context.addLifecycleListener(listener);
context.setName(cn.getName());
context.setPath(cn.getPath());
context.setWebappVersion(cn.getVersion());
context.setDocBase(cn.getBaseName() + ".war");
// 添加StandardContext到当前Host中
host.addChild(context);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("hostConfig.deployWar.error", war.getAbsolutePath()), t);
} finally {
// ...
}
// ...
}

到这里StandardContext算是创建了,并且是Host的子容器,然后回到LifecycleBase.start(),执行startInternal()->StandardHaost.startInternal()->ContainerBase.startInternal(),最终又回到父类ContainerBase的startIniternal()方法中,重复执行StandardContext的事件监听ContextConfig和startInternal():

  1. ContextConfig的事件监听中,会加载项目的web.xml文件
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
java复制代码    @Override
public void lifecycleEvent(LifecycleEvent event) {
// ...
// Process the event that has occurred
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
// 加载web.xml文件
configureStart();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
// Restore docBase for management tools
if (originalDocBase != null) {
context.setDocBase(originalDocBase);
}
} else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
configureStop();
} else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
init();
} else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
destroy();
}
}
protected synchronized void configureStart() {
// ...
webConfig();
// ...
}
// 为了简单理解,省略了很多步骤的代码
protected void webConfig() {
// ...
WebXml webXml = createWebXml();
// ...
if (!webXml.isMetadataComplete()) {
// ...
// Step 9. Apply merged web.xml to Context
if (ok) {
configureContext(webXml);
}
}
// ...
}
// 解析web.xml配置的信息
private void configureContext(WebXml webxml) {
// ...
// 加载Filter们
for (FilterDef filter : webxml.getFilters().values()) {
if (filter.getAsyncSupported() == null) {
filter.setAsyncSupported("false");
}
context.addFilterDef(filter);
}
for (FilterMap filterMap : webxml.getFilterMappings()) {
context.addFilterMap(filterMap);
}
// ...
// 加载Servlet们
for (ServletDef servlet : webxml.getServlets().values()) {
Wrapper wrapper = context.createWrapper();
// ...
wrapper.setOverridable(servlet.isOverridable());
// 添加到StandardContext的child中,且之后在startInternal()中初始化
context.addChild(wrapper);
}
for (Entry<String, String> entry :
webxml.getServletMappings().entrySet()) {
context.addServletMappingDecoded(entry.getKey(), entry.getValue());
}
// 加载默认页面
for (String welcomeFile : webxml.getWelcomeFiles()) {
if (welcomeFile != null && welcomeFile.length() > 0) {
context.addWelcomeFile(welcomeFile);
}
}
// ...
}
  1. 进入StandardContext.startIniternal()中
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
java复制代码    protected synchronized void startInternal() throws LifecycleException {
// ...
// Call ServletContainerInitializers,调用ServletContainerInitializers的方法
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
initializers.entrySet()) {
try {
entry.getKey().onStartup(entry.getValue(), getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
// 运行项目中配置的监听器方法
if (ok) {
if (!listenerStart()) {
log.error(sm.getString("standardContext.listenerFail"));
ok = false;
}
}
// ...
// 初始化servlet们
if (ok) {
if (!loadOnStartup(findChildren())){
log.error(sm.getString("standardContext.servletFail"));
ok = false;
}
}
}
public boolean listenerStart() {
// ...
for (Object instance : instances) {
if (!(instance instanceof ServletContextListener)) {
continue;
}
ServletContextListener listener = (ServletContextListener) instance;
try {
fireContainerEvent("beforeContextInitialized", listener);
if (noPluggabilityListeners.contains(listener)) {
// 应用上下文监听
listener.contextInitialized(tldEvent);
} else {
listener.contextInitialized(event);
}
fireContainerEvent("afterContextInitialized", listener);
} catch (Throwable t) {
// ...
}
}
return ok;
}
public boolean loadOnStartup(Container children[]) {
// ...
for (ArrayList<Wrapper> list : map.values()) {
for (Wrapper wrapper : list) {
try {
// 循环加载servlets
wrapper.load();
} catch (ServletException e) {
// ...
}
}
}
return true;
}

监听:这个监听就是web.xml中配置的,就是启动spring容器的入口

1
2
3
4
xml复制代码<!-- listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

初始化servlet:StandardContext.loadOnStartup()->StandardWrapper.load()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码@Override
public synchronized void load() throws ServletException {
instance = loadServlet();
if (!instanceInitialized) {
initServlet(instance);
}
// ...
}

private synchronized void initServlet(Servlet servlet)
throws ServletException {
// ...
servlet.init(facade);
// ...
}

最后调用的是:GenericServlet.init()

1
2
3
4
5
java复制代码@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}

GenericServlet.init()->HttpServletBean.init()->FramworkServlet.initServletBean(),此时已经进入spring-webmvc.jar

1
2
3
4
5
java复制代码public final void init() throws ServletException {
// ...
this.initServletBean();
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码    protected final void initServletBean() throws ServletException {
// ...
try {
// 初始化spring容器
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} // ...
}
protected WebApplicationContext initWebApplicationContext() {
// ...
if (!this.refreshEventReceived) {
// 此处就是启动DispatcherServlet七大组件的地方!!!
this.onRefresh(wac);
}
// ...
return wac;
}

最后的最后进入:DispatcherServlet.onRefresh()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码protected void onRefresh(ApplicationContext context) {
this.initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}

最后附上一张DispatcherSerlvet的类图

image-20211026180857449.png

2)还有个Connector的初始化:connector.start()->LifecycleBase.start()->Connector.startIniternal()->protocalHandler.start()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java复制代码    protected void startInternal() throws LifecycleException {

// Validate settings before starting
if (getPort() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPort())));
}

setState(LifecycleState.STARTING);

try {
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
}

总结一下子:

  1. Tomcat的启动
* 启动脚本**startup.sh**,最终执行Bootstrap.main(),且会把命令(start、stop等)作为参数传入,不同参数会调用不同的方法
* 当命令是start时,**Bootstrap.main()**会调用**Catalina.load()**和**Catalina.start()**
  1. Tomcat组件的加载:load()
* 在Catalina.load()中,解析**conf/server.xml**,最后调用getServer.init(),对**server**初始化
4. 调用getServer.init(),会进入**LifecycleBase.init()**,这个方法中会先这是server状态为initializing且发布事件,再调用StandardServer.initInternal()
5. 在StandardServer.initInternal()中,会循环调用service.init()方法,会先进入LifecycleBase.init(),然后进入**StandardService.initInternal()**
6. 在StandardService.initInternal()中会初始化**engine**和**connectors**
  1. Tomcat容器的加载:start()
* Catalina.start(),最后调用getServer.start(),进入LifecycleBase.start(),最后进入StandardServer.startIniternal()
2. 在**StandardServer.startIniternal**()中,会启动engine.start()和connector.start()
3. 在engine.start()中,调用**ContainerBase.startIniternal()**,会将子容器Host的启动任务提交到线程池中,**Host容器启动**过程:
    * 先发布事件,且HostConfig监听到这个事件,在HostConfig中会发布web项目,且创建当前web项目的StandardContext,然后把这个**StandardContext添加到Host的子容器中**
    * 然后执行StandardHost.startIniternal(),这个方法中又回到父类ContainerBase.startIniternal(),然后**重复提交StandardContext的启动任务到线程池中**
4. **StandardContext的启动过程**:
    * 发布事件,ContextConfig监听到这个事件,ContextConfig中加载并**解析项目的web.xml文件**,初始化配置的Listener、Filter、Servlet等信息,**servlet会解析成Wrapper**,**然后添加到Context的子容器中**
    * 然后调用**StandardContext.startIniternal**(),启动Context,这里会调用web.xml配置的监听**contextInitialized(),spring容器在这里得到创建**
    * 在StandardContext.startIniternal()中,然后加载Servlet,最终会调用spring-webmvc.jar中**DispatcherSerlvet.onRefresh()**,**加载Serlvet的七大组件**

再来个简单版的总结

Tomcat启动分成2个部分:

  1. 组件的初始化
  2. 容器的启动

其中组件包括:Server->Services->Engine->Connectors
容器包括:Engine->StandardHost->StandardContext->StandardWrapper

web项目的加载、Spring容器的初始化入口、Servlet容器的加载都在第二步,也就是Catalina.start()中

  • web项目的加载:在启动Host容器前发布的事件,也就是监听HostConfig.start()中,并且创建子容器StandardContext
  • Spring容器的初始化入口:在StandardContext启动过程中执行了web.xml中配置的ServletContextListener的实现类的contextInitialized()
  • Servlet容器的加载:在StandardContext启动过程中执行的loadOnStartup(),最终调用DispatcherServlet.onRefresh(),初始化了Servlet的九大组件

留个大疑问

上文中的ServletContainerInitializer的作用是啥?有什么应用?可以怎么拓展?

作用:它是Servlet3.0提供的接口,只有一个方法,主要作用替代web.xml,通过初始化自定义的Listener、Filter、Servlet等信息

1
2
3
4
5
6
7
java复制代码public interface ServletContainerInitializer {
/**
* @param c 启动时初始化的类
* @param ctx web应用的servlet上下文
*/
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}

应用:spring-web.jar中,SpringServletContainerInitializer实现了此接口

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
java复制代码// 1)通过此注解将WebApplicationInitializer类,添加到onStartup方法的第一个参数中
@HandlesTypes({WebApplicationInitializer.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {
public SpringServletContainerInitializer() {
}

public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();

while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 2)创建WebApplicationInitializer对象
initializers.add((WebApplicationInitializer)waiClass.newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}

if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
var4 = initializers.iterator();

while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
// 3)调用WebApplicationInitializer的方法初始化
initializer.onStartup(servletContext);
}

}
}
}

SpringServletContainerInitializer在Tomcat启动时,容器初始化阶段初始化StandardContext时,被调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码    protected synchronized void startInternal() throws LifecycleException {
// Call ServletContainerInitializers
for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : initializers.entrySet()) {
try {
// 循环多个ServletContainerInitializer,并调用onStartup()
entry.getKey().onStartup(entry.getValue(), getServletContext());
} catch (ServletException e) {
log.error(sm.getString("standardContext.sciFail"), e);
ok = false;
break;
}
}
}

SpringServletContainerInitializer是如何加载到的?毕竟在第三方jar包中,也是在Tomcat启动初始化容器StandardContext之前,发布的事件,在事件监听ContextConfig中加载的:(方法链路:lifecycleEvent()->configureStart()->webConfig()->processServletContainerInitializers()->WebappServiceLoader.load()),spring-web.jar的**classpath/META-INF/services/**路径下配置了需要初始化的ServletContianerInitializer,由Tomcat的ContextConfig加载初始化,在StandardContext中调用

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码    protected void processServletContainerInitializers(){	
// 1) 指定类型为ServletContainerInitializer
WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
detectedScis = loader.load(ServletContainerInitializer.class);
// ...
}

// 2)加载META-INF/services/路径下
private static final String SERVICES = "META-INF/services/";
public List<T> load(Class<T> serviceType) throws IOException {
String configFile = SERVICES + serviceType.getName();
// ...
}

image-20211107180834566.png

自定义:ServletContainerInitializer

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
java复制代码//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来;
//传入感兴趣的类型;
@HandlesTypes(value={HelloService.class})
public class MyServletContainerInitializer implements ServletContainerInitializer {

/**
* 应用启动的时候,会运行onStartup方法;
*
* Set<Class<?>> arg0:感兴趣的类型的所有子类型;
* ServletContext arg1:代表当前Web应用的ServletContext;一个Web应用一个ServletContext;
*
* 1)、使用ServletContext注册Web组件(Servlet、Filter、Listener)
* 2)、使用编码的方式,在项目启动的时候给ServletContext里面添加组件;
* 必须在项目启动的时候来添加;
* 1)、ServletContainerInitializer得到的ServletContext;
* 2)、ServletContextListener得到的ServletContext;
*/
@Override
public void onStartup(Set<Class<?>> arg0, ServletContext sc) throws ServletException {
// TODO Auto-generated method stub
System.out.println("感兴趣的类型:");
for (Class<?> claz : arg0) {
System.out.println(claz);
}

//注册组件 ServletRegistration
ServletRegistration.Dynamic servlet = sc.addServlet("userServlet", new UserServlet());
//配置servlet的映射信息
servlet.addMapping("/user");


//注册Listener
sc.addListener(UserListener.class);

//注册Filter FilterRegistration
FilterRegistration.Dynamic filter = sc.addFilter("userFilter", UserFilter.class);
//配置Filter的映射信息
filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

}

}

参考:

😈如果有错误请大家指正…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%