springboot web server 启动逻辑

springboot 的一个方便之处就是集成了 web server 进去,接着上一篇继续来看下这个 web server 的启动过程
这边是基于 springboot 的 2.2.9.RELEASE 版本,整个 springboot 体系主体就是看
org.springframework.context.support.AbstractApplicationContext#refresh
刷新方法,而启动 web server 的方法就是在其中的 onRefresh

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
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// ------------------> ‼️就是这里
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

跟进去其实本身是啥都不做的,由具体的实现类子类去做各自的处理
org.springframework.context.support.AbstractApplicationContext#onRefresh

1
2
3
4
5
6
7
8
9
10
/**
* Template method which can be overridden to add context-specific refresh work.
* Called on initialization of special beans, before instantiation of singletons.
* <p>This implementation is empty.
* @throws BeansException in case of errors
* @see #refresh()
*/
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}

看具体的实现类里就有我们的主角
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

1
2
3
4
5
6
7
8
9
10
protected void onRefresh() {
super.onRefresh();

try {
// -------------> 主要就是这里,创建 webserver
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}

具体的就是一些前置处理
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}

this.initPropertySources();
}

初始的 webServer 和 servletContext 都是 null,需要进行初始化
先是获取 WebServer 工厂,
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getWebServerFactory

1
2
3
4
5
6
7
8
9
10
11
protected ServletWebServerFactory getWebServerFactory() {
String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
} else if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
} else {
return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
}

获取了类型是 ServletWebServerFactory 的 bean,然后再回来就是调用的接口方法
org.springframework.boot.web.servlet.server.ServletWebServerFactory#getWebServer
根据具体的 factory 来生成对应的譬如 tomcat 的 factory,
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}

最后一行就是创建 TomcatWebServer,
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getTomcatWebServer

1
2
3
4
5
6
7
8
9
10
/**
* Factory method called to create the {@link TomcatWebServer}. Subclasses can
* override this method to return a different {@link TomcatWebServer} or apply
* additional processing to the Tomcat server.
* @param tomcat the Tomcat server.
* @return a new {@link TomcatWebServer} instance
*/
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0);
}

这里面就开始 new 了一个 TomcatWebServer,
org.springframework.boot.web.embedded.tomcat.TomcatWebServer#TomcatWebServer(org.apache.catalina.startup.Tomcat, boolean)

1
2
3
4
5
6
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}

再调用里面的初始化方法,
org.springframework.boot.web.embedded.tomcat.TomcatWebServer#initialize

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
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();

Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
removeServiceConnectors();
}
});

// Start the server to trigger initialization listeners
this.tomcat.start();

// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();

try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}

// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread();
}
catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
```
这里就是继续调用 `org.apache.catalina.startup.Tomcat#start`
```java
public void start() throws LifecycleException {
this.getServer();
this.server.start();
}
```
获取server, `org.apache.catalina.startup.Tomcat#getServer`
```java
public Server getServer() {
if (this.server != null) {
return this.server;
} else {
System.setProperty("catalina.useNaming", "false");
this.server = new StandardServer();
this.initBaseDir();
ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(this.basedir), (String)null));
this.server.setPort(-1);
Service service = new StandardService();
service.setName("Tomcat");
this.server.addService(service);
return this.server;
}
}

然后就是启动 server,后面可以继续看这个启动 TomcatServer 内部的逻辑