1.继承图
2.概述
我们一般都是使用的web环境,也就是创建的上下文是AnnotationConfigServletWebServerApplicationContext这个上下文,调用refresh这个方法时,会根据自动装配的是tomcat还是其他web服务器来创建一个webserver并启动
3.源码
springboot源码-AnnotationConfigServletWebServerApplicationContext_LouD_dm的博客-CSDN博客
springboot源码-ServletWebServerApplicationContext_LouD_dm的博客-CSDN博客
4.启动流程分析
启动时方法执行顺序是
1.ServletWebServerApplicationContext#refresh
2.AbstractApplicationContext#refresh
3.ServletWebServerApplicationContext#onRefresh
4.AbstractApplicationContext#onRefresh
5.ServletWebServerApplicationContext#finishRefresh
6.AbstractApplicationContext#finishRefresh
AnnotationConfigServletWebServerApplicationContext没有重写refresh方法,这里调用的是
ServletWebServerApplicationContext的refresh方法
@Override
public final void refresh() throws BeansException, IllegalStateException {
try {
//调用父类的refresh方法
super.refresh();
} catch (RuntimeException ex) {
stopAndReleaseWebServer();
throw ex;
}
}
这里又调用了父类的refresh方法,具体在AbstractApplicationContext这个类里
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备在这种情况下使用的bean工厂。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器.
registerBeanPostProcessors(beanFactory);
// 为此上下文初始化消息源。
initMessageSource();
// 为此上下文初始化事件多播器。
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其他特殊bean。
onRefresh();
// 检查侦听器bean并注册它们。
registerListeners();
// 实例化所有剩余的(非延迟初始化)单例。
finishBeanFactoryInitialization(beanFactory);
//最后一步:发布相应的事件。
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免资源悬空。
destroyBeans();
// 重置“活动”标志。
cancelRefresh(ex);
// 将异常传播给呼叫者。
throw ex;
} finally {
// 在Spring的核心中重置常见的自省缓存,因为我们可能不再需要单例bean的元数据...
resetCommonCaches();
}
}
}
注意这里调用了onRefresh方法和finishRefresh方法,ServletWebServerApplicationContext重写了这两个方法,创建和启动webserver
@Override
protected void onRefresh() {
//调用父类的onRefresh方法
super.onRefresh();
try {
//创建webServer嵌入web服务器
createWebServer();
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
@Override
protected void finishRefresh() {
super.finishRefresh();
//启动web server
WebServer webServer = startWebServer();
if (webServer != null) {
//发布web server启动的事件
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
创建webserver
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
//获取WebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
//获取web服务器
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();
}
主要方法getWebServerFactory,这里用到了自动装配,在spring.factories配置文件中有ServletWebServerFactoryAutoConfiguration这个类
在这个类上引入了其他配置类
@Configuration(proxyBeanMethods = false) //不需要代理
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) //注入顺序,采用最低
@ConditionalOnClass(ServletRequest.class) //项目中有ServletRequest这个类才会注入
@ConditionalOnWebApplication(type = Type.SERVLET) //当前环境是SERVLET时才会注入
@EnableConfigurationProperties(ServerProperties.class) // @ConfigurationProperties注解的beans将自动被Environment属性配置,
// 也就是在配置文件中的属性值会自动覆盖到bean里
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, //引入其他配置
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
ServletWebServerFactoryConfiguration这个类里配置有所有的ServletWebServerFactory的bean
package org.springframework.boot.autoconfigure.web.servlet;
import java.util.stream.Collectors;
import javax.servlet.Servlet;
import io.undertow.Undertow;
import org.apache.catalina.startup.Tomcat;
import org.apache.coyote.UpgradeProtocol;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.xnio.SslClientAuthMode;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer;
import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* servlet web 服务器的配置类
*
* 这些应该是常规自动配置类中的 {@code @Import} 以保证
* 他们的执行顺序。
*
* @author Phillip Webb
* @author Dave Syer
* @author Ivan Sopov
* @author Brian Clozel
* @author Stephane Nicoll
* @author Raheela Asalm
* @author Sergey Serdyuk
*/
@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
//保证ServletWebServerFactory这个bean只有一个
//仅搜索当前上下文
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider connectorCustomizers,
ObjectProvider contextCustomizers,
ObjectProvider> protocolHandlerCustomizers) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.getTomcatConnectorCustomizers()
.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatContextCustomizers()
.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatProtocolHandlerCustomizers()
.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
/**
* 如果正在使用 Jetty,则为嵌套配置。
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory(
ObjectProvider serverCustomizers) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
/**
* 如果正在使用 Undertow,则嵌套配置。
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory(
ObjectProvider deploymentInfoCustomizers,
ObjectProvider builderCustomizers) {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.getDeploymentInfoCustomizers()
.addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList()));
factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
}
springboot默认是用tomcat启动的,所以这里默认实现是TomcatServletWebServerFactory
TomcatServletWebServerFactory的getWebServer方法
具体之后在看,这里返回TomcatWebServer
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
//创建一个tomcat
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);
}
在finishRefresh方法里启动webserver,这里webserver的实现是上一步返回的TomcatWebServer
@Override
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try {
addPreviouslyRemovedConnectors();
Connector connector = this.tomcat.getConnector();
if (connector != null && this.autoStart) {
performDeferredLoadOnStartup();
}
checkThatConnectorsHaveStarted();
this.started = true;
logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
+ getContextPath() + "'");
}
catch (ConnectorStartFailedException ex) {
stopSilently();
throw ex;
}
catch (Exception ex) {
if (findBindException(ex) != null) {
throw new PortInUseException(this.tomcat.getConnector().getPort());
}
throw new WebServerException("Unable to start embedded Tomcat server", ex);
}
finally {
Context context = findContext();
ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
}
}