spring boot 中 tomcat启动流程

tomcat初始化

startup.bat
catalina.bat获得基础环境变量

  1. 调用bin\bootstrap.jar 中的 main 方法,创建了一个Bootstrap类
    1.2 调用其init()方法,初始化org.apache.catalina.startup.Catalina类为catalinaDaemon
    1.3 然后调用load(args)方法,调用Catalina的load方法

  2. Catalina类调用load,解析server.xml文件,创建server实例,调用其init方法

  3. StandardServer类的initInternal方法,遍历调用其中service的init方法

  4. StandardService类的initInternal方法,初始engine容器、executor线程池和connectors连接器

  5. Bootstrap类调用start方法,反射调用Catalina中的start方法

  6. Catalina中的start方法,调用Server的start方法,添加jvm钩子函数确保退出时Catalina终止

  7. StandardServer的startInternal方法,遍历调用其中service的start方法

  8. StandardService类的startInternal方法,启动engine容器、executor线程池和connectors连接器(根据版本启动Socket的accept方法等待连接)

  9. 启动StandardEngine容器,调用其startInternal方法,最终调用ContainerBase的startInternal方法,Future模式启动子容器(如Host、Context等,Host、Context初始化也在此时完成),其中Context初始化通过ContextConfig监听器处理。

  10. StandardContext调用startInternal,会依次处理ServletContainerInitializer、Listener处理、Filter处理、加载loadOnStartup的servlet

tomcat请求过程

···忽略Socket处理请求过程,从连接器到容器开始分析

  1. 调用CoyoteAdapter的service方法来封装request和response,解析uri中参数,获得Host、Context等,使用Container的第一个Pipeline管道,调用其invoke方法
  2. vavel调用 StandardEngineValve->StandardHostValve->StandardContextValve->StandardWrapperValve
    2.1 StandardContext中存在Map<String, String> servletMappings来处理请求的uri,找到对应的StandardWrapper名称
    2.2 StandardWrapper中存在ArrayList mappings表明当前servlet支持的uri
  3. 在StandardWrapperValve中完成对过滤器链的执行和servlet的调用
    3.1 首先会创建一个servlet实例来处理当前请求 wrapper.allocate();
    3.2 为当前请求创建过滤器链 ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    3.3 doFilter执行所有过滤操作,之后调用其默认servlet执行service方法

tomcat在Spring Boot中启动流程

  1. Spring Boot自动启动tomcat依靠ServletWebServerFactoryAutoConfiguration自动配置类

当存在ServletRequest类且WebApplication类型为SERVLET时才注册,加载注册顺序最高
注册了ServletWeb自定义服务工厂和tomcat自定义Web服务工厂
注册WebServerFactoryCustomizerBeanPostProcessor类如果为WebServerFactory类型则执行customize方法

@Configuration(proxyBeanMethods = false)
@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);
	}
}
  1. Spring Boot启动过程中ServletWebServerApplicationContext的onRefresh()方法

注册bean,从serverProperties中获得值来初始化webServer工厂参数
忽略的用于.tld 文件扫描的JAR的模式
是否应通过将/附加到路径来重定向对上下文根的请求,默认为true
调用sendRedirect生成的HTTP1.1和更高版本的位置标头将使用相对重定向还是绝对重定向, 默认false相对重定向
是否应启用Tomcat的MBean注册表,默认不启用
tomcat启动

protected void onRefresh() {
	// TomcatServletWebServerFactory注册初始化
	super.onRefresh();
	try {
		// 创建web服务器
		createWebServer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}
  1. createWebServer创建web服务器
private void createWebServer() {
	WebServer webServer = this.webServer;
	ServletContext servletContext = getServletContext();
	if (webServer == null && servletContext == null) {
		// 从IOC容器中获得ServletWebServerFactory
		ServletWebServerFactory factory = getWebServerFactory();
		// 获得WebServer
		this.webServer = factory.getWebServer(getSelfInitializer());
		getBeanFactory().registerSingleton("webServerGracefulShutdown",
				new WebServerGracefulShutdownLifecycle(this.webServer));
		getBeanFactory().registerSingleton("webServerStartStop",
				new WebServerStartStopLifecycle(this, this.webServer));
	}
	else if (servletContext != null) {
		try {
			getSelfInitializer().onStartup(servletContext);
		}
		catch (ServletException ex) {
			throw new ApplicationContextException("Cannot initialize servlet context", ex);
		}
	}
	initPropertySources();
}
  1. getWebServer从工厂中获得Web服务器

创建tomcat,临时文件存放路径
依次创建server、service、connector、engine、host、context和wrapper
tomcat.start启动服务器

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);
	// 创建StandardServer、StandardService并将连接器传入service中
	tomcat.getService().addConnector(connector);
	// 定制连接器的一些参数(如port)
	customizeConnector(connector);
	// 确保连接器被传入service中
	tomcat.setConnector(connector);
	// 创建StandardEngine加入service中,创建StandardHost放入Engine的child中,且自动部署标识为false
	tomcat.getHost().setAutoDeploy(false);
	configureEngine(tomcat.getEngine());
	// 为service添加附加连接器
	for (Connector additionalConnector : this.additionalTomcatConnectors) {
		tomcat.getService().addConnector(additionalConnector);
	}
	// 创建TomcatEmbeddedContext,为其添加StandardWrapper子容器(默认名称为default) 
	prepareContext(tomcat.getHost(), initializers);
	// 启动tomcat
	return getTomcatWebServer(tomcat);
}
  1. TomcatWebServer中initialize方法启动tomcat,调用server的start方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值