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
    评论
Spring Boot中,可以通过配置文件来自定义Tomcat的配置。默认情况下,Spring Boot使用嵌入式的Tomcat作为Servlet容器。Tomcat的默认配置参数可以在ServerProperties类中找到,其中的静态内部类Threads中定义了最大工作线程数(worker threads)的默认值。 关于Tomcat的配置,可以在application.properties文件中进行配置。通用的Servlet容器配置以"server"作为前缀,而Tomcat特有的配置以"server.tomcat"作为前缀。 以下是一些常用的Tomcat配置示例: - 设置Tomcat的端口号: `server.port=8080` - 设置Tomcat的上下文路径: `server.servlet.context-path=/myapp` - 配置Tomcat的连接器属性: `server.tomcat.*` 请注意,以上只是一些常见的配置示例,你还可以根据需要进行更多的Tomcat配置。通过在application.properties文件中添加对应的属性,可以根据需求来自定义Tomcat的行为。 你也可以参考Spring Boot官方文档中关于Tomcat配置的部分进行更详细的了解和配置。 - [ServerProperties - Spring Boot Reference Guide](https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#server-properties) - [Spring Boot Documentation - Embedded Servlet Containers](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-embedded-container) - [Spring Boot Documentation - Common Application Properties](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties)<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [[SpringBoot Server]SpringBoot tomcat配置](https://blog.csdn.net/mdwsmg/article/details/126830647)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [SpringBootTomcat配置(学习SpringBoot实战)](https://blog.csdn.net/m0_66557301/article/details/124418970)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值