SpringBoot源码分析(三) -- Tomcat启动流程
onRefresh 方法
//这段代码位置在:org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
protected void onRefresh() {
//在父类的onRefresh方法中初始化了主题资源
super.onRefresh();
try {
//创建web服务
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
createWebServer 方法
//这段代码位置在:org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
//第一次进来,webServer和servletContext都为null
if (webServer == null && servletContext == null) {
//getWebServerFactory方法直接从beanFactory中获取ServletWebServerFactory类
//getWebServerFactory方法会创建DispatcherServlet对象,并添加到beanFactory中去,对应的beanName为dispatcherServlet
ServletWebServerFactory factory = getWebServerFactory();
//这个方法为wrapper设置了servletClass为DispatcherServlet
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();
}
//获取WebServerFactory
protected ServletWebServerFactory getWebServerFactory() {
// Use bean names so that we don't consider the hierarchy
String[] beanNames = getBeanFactory()
.getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start ServletWebServerApplicationContext due to missing "
+ "ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start ServletWebServerApplicationContext due to multiple "
+ "ServletWebServerFactory beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
//获取ServletContextInitializer
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return this::selfInitialize;
}
getWebServer 方法
//这段代码位置在:org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
public WebServer getWebServer(ServletContextInitializer... initializers) {
//创建tomcat,直接new出来的
Tomcat tomcat = new Tomcat();
//设置工作目录
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
//设置安装目录
tomcat.setBaseDir(baseDir.getAbsolutePath());
//初始化tomcat的连接器
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
//设置自动部署为false
tomcat.getHost().setAutoDeploy(false);
//配置引擎
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
//准备context,这个重要,跟进去
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
//初始化链接器
protected void customizeConnector(Connector connector) {
int port = (getPort() >= 0) ? getPort() : 0;
connector.setPort(port);
if (StringUtils.hasText(this.getServerHeader())) {
connector.setAttribute("server", this.getServerHeader());
}
if (connector.getProtocolHandler() instanceof AbstractProtocol) {
customizeProtocol((AbstractProtocol<?>) connector.getProtocolHandler());
}
if (getUriEncoding() != null) {
connector.setURIEncoding(getUriEncoding().name());
}
// Don't bind to the socket prematurely if ApplicationContext is slow to start
connector.setProperty("bindOnInit", "false");
if (getSsl() != null && getSsl().isEnabled()) {
customizeSsl(connector);
}
TomcatConnectorCustomizer compression = new CompressionConnectorCustomizer(
getCompression());
compression.customize(connector);
for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) {
customizer.customize(connector);
}
}
//配置引擎,添加阀
private void configureEngine(Engine engine) {
engine.setBackgroundProcessorDelay(this.backgroundProcessorDelay);
for (Valve valve : this.engineValves) {
engine.getPipeline().addValve(valve);
}
}
prepareContext 方法
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
//这里为null
File documentRoot = getValidDocumentRoot();
//创建TomcatEmbeddedContext对象
TomcatEmbeddedContext context = new TomcatEmbeddedContext();
if (documentRoot != null) {
context.setResources(new LoaderHidingResourceRoot(context));
}
//为TomcatEmbeddedContext对象设置属性
context.setName(getContextPath());
context.setDisplayName(getDisplayName());
context.setPath(getContextPath());
File docBase = (documentRoot != null) ? documentRoot
: createTempDir("tomcat-docbase");
context.setDocBase(docBase.getAbsolutePath());
context.addLifecycleListener(new FixContextListener());
context.setParentClassLoader(
(this.resourceLoader != null) ? this.resourceLoader.getClassLoader()
: ClassUtils.getDefaultClassLoader());
resetDefaultLocaleMapping(context);
addLocaleMappings(context);
context.setUseRelativeRedirects(false);
configureTldSkipPatterns(context);
WebappLoader loader = new WebappLoader(context.getParentClassLoader());
loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
loader.setDelegate(true);
context.setLoader(loader);
if (isRegisterDefaultServlet()) {
//这里添加默认的servlet
addDefaultServlet(context);
}
if (shouldRegisterJspServlet()) {
addJspServlet(context);
addJasperInitializer(context);
}
context.addLifecycleListener(new StaticResourceConfigurer(context));
ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
//把context添加到host中
host.addChild(context);
//配置tomcat
configureContext(context, initializersToUse);
//空实现,等以后子类实现
postProcessContext(context);
}
//添加默认的servlet
private void addDefaultServlet(Context context) {
//创建wrapper对象,servlet包裹在Wrapper对象中,详见tomcat源码系列
Wrapper defaultServlet = context.createWrapper();
defaultServlet.setName("default");
//设置servlet的全路径,这里用的是DefaultServlet。最后会通过反射创建servlet类
defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet");
defaultServlet.addInitParameter("debug", "0");
defaultServlet.addInitParameter("listings", "false");
defaultServlet.setLoadOnStartup(1);
// Otherwise the default location of a Spring DispatcherServlet cannot be set
defaultServlet.setOverridable(true);
//把wrapper添加到context中去
context.addChild(defaultServlet);
//添加servlet映射
context.addServletMappingDecoded("/", "default");
}
//配置tomcat
protected void configureContext(Context context,
ServletContextInitializer[] initializers) {
//创建一个TomcatStarter类,这个类是为了初始化时在它的onStartup方法中调用ServletContextInitializer
//它的内部维护了一个ServletContextInitializer的数组,构造方法初始化了这个数组
//onStartup方法中遍历执行数组
TomcatStarter starter = new TomcatStarter(initializers);
if (context instanceof TomcatEmbeddedContext) {
TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext) context;
embeddedContext.setStarter(starter);
embeddedContext.setFailCtxIfServletStartFails(true);
}
context.addServletContainerInitializer(starter, NO_CLASSES);
for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) {
context.addLifecycleListener(lifecycleListener);
}
//在context的pipeline中添加valve
for (Valve valve : this.contextValves) {
context.getPipeline().addValve(valve);
}
//配置错误页面
for (ErrorPage errorPage : getErrorPages()) {
new TomcatErrorPage(errorPage).addToContext(context);
}
//配置mime映射
for (MimeMappings.Mapping mapping : getMimeMappings()) {
context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
}
//配置session
configureSession(context);
for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) {
customizer.customize(context);
}
}
getTomcatWebServer 方法
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
//直接创建了一个TomcatWebServer类
return new TomcatWebServer(tomcat, getPort() >= 0);
}
TomcatWebServer 类
//构造方法
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
//维护了一个tomcat的实例
this.tomcat = tomcat;
this.autoStart = autoStart;
//初始化方法,跟进去
initialize();
}
//初始化方法
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
//启动tomcat
//这里面会为Wrapper设置servletClass为dispatcherServlet,详见流程图
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();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
DispatcherServlet 的创建
//当前方法位置在:org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration.DispatcherServletConfiguration#dispatcherServlet
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
//创建DispatcherServlet
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(
this.webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(
this.webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(
this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setEnableLoggingRequestDetails(
this.httpProperties.isLogRequestDetails());
return dispatcherServlet;
}
注意:DispatcherServlet的初始化在第一次请求访问时进行初始化