容器启动全局流程解析
启动前准备
在 SpringApplication 构造方法中根据 classpath 下是否存在特定类来决定容器类型(SERVLET、REACTIVE、NONE),并赋值给 webApplicationType 属性。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.webApplicationType = WebApplicationType.deduceFromClasspath();
}
static WebApplicationType deduceFromClasspath() {
// 存在 reactive.DispatcherHandler 且不存在 servlet.DispatcherServlet 和 org.glassfish.jersey.servlet.ServletContainer (Oracle WEB Server)时,视为 REACTIVE 环境
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
// 如果不存在 javax.servlet.Servlet 或 ConfigurableWebApplicationContext 视为 NONE (非 WEB)环境
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
// 默认视为 SERVLET 环境
return WebApplicationType.SERVLET;
}
在 SpringApplication 的 createApplicationContext 方法中根据 webApplicationType 属性创建对应的上下文。
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
// AnnotationConfigServletWebServerApplicationContext
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
// AnnotationConfigReactiveWebServerApplicationContext
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
// AnnotationConfigApplicationContext
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
WEBServer 创建
在 refresh 方法中调用由 ServletWebServerApplicationContext 实现的 onRefresh 子方法,通过 createWebServer 方法完成 WEBServer 的创建。
// ServletWebServerApplicationContext.java
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 获取用于创建 webServer 的工厂类,一般情况是:TomcatServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 创建 Tomcat WEBServer
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
// TomcatServletWebServerFactory.java
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
// ...
return getTomcatWebServer(tomcat);
}
WEBServer 容器启动
在 refresh 方法中调用由 ServletWebServerApplicationContext 实现的 finishRefresh 子方法,通过 startWebServer 方法完成 WEBServer 启动。
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startWebServer();
if (webServer != null) {
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
private WebServer startWebServer() {
WebServer webServer = this.webServer;
if (webServer != null) {
// 启动 webServer
webServer.start();
}
return webServer;
}
WEB 容器工厂类加载解析
WEBServer 创建时通过 getWebServerFactory 方法获取工厂类,默认是 TomcatServletWebServerFactory 对象,那这个对象是何时加载到容器中的呢?
EnableAutoConfiguration
@SpringBootApplication 注解上有 @EnableAutoConfiguration 注解,并通过 @Import 引入了 AutoConfigurationImportSelector,用于处理自动配置。
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
public class AutoConfigurationImportSelector implements DeferredImportSelector {
// 返回需要导入的配置类
}
需要自动配置的类定义在 spring-boot-autoconfigure/META-INF/spring.factories
中,其中就有 ServletWebServerFactoryAutoConfiguration 。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
ServletWebServerFactoryAutoConfiguration
ServletWebServerFactoryAutoConfiguration 用于处理 Servlet WEB 容器的配置类,它引入了 EmbeddedTomcat 配置类,并配置了 ServletWebServerFactoryCustomizer 对象用于配置 ServletWebServerFactory。
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
}
因为当前是 Servlet 环境,且引入了 org.springframework.boot:spring-boot-starter-tomcat
依赖,故此处会创建 TomcatServletWebServerFactory 对象注册到 BeanFactory 中,用于后续创建 Tomcat WEBServer。
@Configuration
class ServletWebServerFactoryConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
}
WEB 容器配置解析
ServerProperties
以 Tomcat 容器为例,调整如下两个配置,WEBServer 属性配置保存在 ServerProperties 中。
server.port=8082
server.tomcat.max-threads=201
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
private Integer port;
private final Tomcat tomcat = new Tomcat();
public static class Tomcat {
private int maxThreads = 200;
}
// ...
}
WebServerFactoryCustomizer
在 ServletWebServerFactoryAutoConfiguration 中向容器中注册了 ServletWebServerFactoryCustomizer 和 TomcatServletWebServerFactoryCustomizer 对象用于调整 WebServer 配置。
@FunctionalInterface
public interface WebServerFactoryCustomizer<T extends WebServerFactory> {
void customize(T factory);
}
WebServerFactoryCustomizer 实现类在 WebServerFactoryCustomizerBeanPostProcessor 的 postProcessBeforeInitialization 方法中调用。
public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
private ListableBeanFactory beanFactory;
private List<WebServerFactoryCustomizer<?>> customizers;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebServerFactory) {
postProcessBeforeInitialization((WebServerFactory) bean);
}
return bean;
}
@SuppressWarnings("unchecked")
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
// getCustomizers():获取所有 WebServerFactoryCustomizer 实现类对象
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
// 调用 customize 方法
.invoke((customizer) -> customizer.customize(webServerFactory));
}
}
ServletWebServerFactoryCustomizer
以 ServletWebServerFactoryCustomizer 为例,介绍 server.port
属性是如何设置到 WebServer 中的。
ServletWebServerFactoryAutoConfiguration 自动配置类会注册 ServletWebServerFactoryCustomizer Bean 实例,ServerProperties 对象中保存了配置项 server.port
的值。
WebServer 容器创建时会调用 getWebServerFactory 方法获取已注册的 TomcatServletWebServerFactory Bean 实例,Bean 创建时通过 WebServerFactoryCustomizerBeanPostProcessor 后置处理器调用 WebServerFactoryCustomizer 实现,对 TomcatServletWebServerFactory 做配置。
ServletWebServerFactoryCustomizer 在 customize 方法中将 server.port
属性设置到 ConfigurableServletWebServerFactory 中,其它的 Customizer 也基本是同样的处理方式。
最终调用 TomcatServletWebServerFactory 的 getWebServer 创建 WebServer 时,将保存在自身的 server.port
属性设置到 Connector 中。