Springboot embedded Tomcat

​Springboot内置Tomcat启动过程

最近工作中需要在Tomcat端口启动后立即获取随机的端口号,所以研究了下Springboot相关的源码,在此记录下。

1. maven dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>

Here is the dependency hierarchy of spring-boot-starter-web:
在这里插入图片描述

2. 启动入口

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			// step1: create context
			// 实例化AnnotationConfigServletWebServerApplicationContext类
			context = createApplicationContext();
			// step2: prepare context
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
			// step3: refresh context
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

2.1 create context

利用反射创建 AnnotationConfigServletWebServerApplicationContext类的实例,但
在这里插入图片描述

2.2 refresh context

在这里插入图片描述
在这里插入图片描述
这里的applicationContext就是createApplicationContext()方法创建的AnnotationConfigServletWebServerApplicationContext实例,但AnnotationConfigServletWebServerApplicationContext没有实现refresh()方法,它的父类
ServletWebServerApplicationContext中定义了该方法
在这里插入图片描述
最终调用到了AbstractApplicationContext类的refresh()方法
附:AnnotationConfigServletWebServerApplicationContext & ServletWebServerApplicationContext & AbstractApplicationContext的继承关系
在这里插入图片描述
AbstractApplicationContext类的refresh 方法,如下图:
重点关注两个方法:onRefresh() & finishRefresh()
在这里插入图片描述

2.2.1 创建web server

onRefresh()
根据java语言的多态性,会调用子类ServletWebServerApplicationContext的onRefresh(),在这里插入图片描述
至此,看到了createWebServer(),这就是tomcat开始创建的入口。为了更好的理解内置Tomcat的启动,该部分放到后面仔细研究。

2.2.2 publish event

finishRefresh()
在这里插入图片描述
getLifecycleProcessor()返回的是DefaultLifecycleProcessor, onRefresh方法调用了startBeans方法

在这里插入图片描述
下面是从startBeans方法开始到WebServerStartStopLifecycle.start()方法的调用类图
在这里插入图片描述
源码:
在这里插入图片描述
LifecycleGroup是DefaultLifecycleProcessor的内部类,该内部类维护了Lifecycle beans的启动和停止;
因为这些有声明周期属性的beans的启动和停止需要按照一定的规则及顺序执行,所以需要用一个类封装这些复杂的属性和规则。
在这里插入图片描述
内部类的start()方法调用了外部类中的方法doStart():
在这里插入图片描述
doStart()方法调用了bean的start方法,对于WebServerStartStopLifecycle的start()方法如下:
真正开启tomcat 并开始监听端口
发布ServletWebServerInitializedEvent事件,我们可以通过监听该事件来获取tomcat的随机端口号。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面就是端口号的获取和绑定
在这里插入图片描述

至此,我们了解了embedded tomcat的在springboot中context中的启动流程。下面回头关注embedded tomcat启动的源码

3. 创建Embedded Tomcat

在章节 2.3.1 onRefresh() 中,看到了tomcat创建的方法:ServletWebServerApplicationContext.onRefresh().
在这里插入图片描述
Tomcat的启动分为两步init 和 start, 会对应到源码的两个方法: init() 和 startInternal()。

3.1 overview

对照图中的组件之间的关系来分析源码更轻松
图1: 来自CSDN课程:
在这里插入图片描述
图2:类图
在这里插入图片描述
所有组件都需要init & start & destroy & stop, 故使其继承抽象类 LifecycleBase ,在LifecycleBase中有init() & start()方法,
在这里插入图片描述
start() => init() => initInternal()
=> startInternal()
initInternal()方法 & startInternal() 在该抽象类中是一个抽象方法,各个组件会实现自己的.
在子类中实现的startInternal要 state为 STARTING,状态的更新会触发START_EVENT
在这里插入图片描述

3.2 从获取ServletWebServerFactory开始

在createWebServer方法中,首先获取ServletWebServerFactory。 这个bean在context中可以获取到
在这里插入图片描述
有三个实现类,我们使用的是TomcatServletWebServerFactory。该方法只是获取到一个paused web server的实例,只有在ApplicationContext在完全刷新后,才能connect to 这个server.
在这里插入图片描述
ServletWebServerFactory 是用来创建embedded Webserver的:
在这里插入图片描述

3.3 创建web server

在这里插入图片描述

在这里插入图片描述
重点关注 tomcat.start()
在这里插入图片描述

此时,已经创建了server,所以getServer()直接返回之前创建的server. 这个重点看 server.start()
在这里插入图片描述

3.3.1 初始化

先关注这个init()方法, 这个方法里面会有server中一系列组件的init;

Flowchart
Created with Raphaël 2.3.0 init start StandardServer.initInternal() service.init() LifecycleBase.init() StandardService.initInternal() engine.init() LifecycleBase.init() StandardEngine.initInternal() executor.init() LifecycleBase.init() connector.init() LifecycleBase.init() Connector.initInternal() ProtocolHandler.init() AbstractHttp11Protocol.init() AbstractProtocol.init() AbstractEndpoint.init() init end
源码

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
调用子类自己的initInternal()方法,service中包含三个组件的初始化:

  • engine
  • executor
  • connector

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3.2 启动

Flowchart
Created with Raphaël 2.3.0 start LifecycleBase.start() StandardServer.startInternal() -> service.start() LifecycleBase.start() StandardEngine.startInternal() standard container startup -> super.startInternal() ContainerBase.startInternal() -> start child container start child container -> AbstractExecutorService.submit() another Thread -> StartChild.call() -> child.start() another Thread -> LifecycleBase.start() another Thread -> StandardContext.startInternal() another Thread -> TomcatStarter.onStartup another Thread -> TomcatStarter.onStartup -> ServletContextInitializer.onStartup() another Thread -> ServletWebServerApplicatioinContext.selfInitialize() end
类图

在这里插入图片描述

源码入口

在这里插入图片描述
然后开始进行server中各个组件的start,start顺序与初始化顺序相似。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值