springboot源码分析-内嵌tomcat启动流程分析

1.继承图

springboot源码分析-内嵌tomcat启动流程分析_第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这个类

springboot源码分析-内嵌tomcat启动流程分析_第2张图片

 在这个类上引入了其他配置类

@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());
			}
		}
	}

你可能感兴趣的:(springboot源码分析,tomcat,java,spring,boot)