【SpringBoot】SpringBoot内置Servlet容器源码分析-Tomcat

news2025/2/22 23:36:35

自动装配加载 ServletWebServerFactoryAutoConfiguration

在这里插入图片描述
在自动装配的时候,会加载spring.factories,并且添加到IOC容器中。这里包含web自动配置类ServletWebServerFactoryAutoConfiguration ,其中本类中注入三个bean,分别是EmbeddedTomcat\EmbeddedJetty\EmbeddedUndertow, 以及可以添加自定义BD的BeanPostProcessorsRegistrar

@Configuration(proxyBeanMethods = false) // 配置类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) // 自动装配的顺序
@ConditionalOnClass(ServletRequest.class) //  引入Servlet的依赖才生效
@ConditionalOnWebApplication(type = Type.SERVLET) // 当Web容器是Servlet才生效
@EnableConfigurationProperties(ServerProperties.class) // 关联对应的属性配置类
// 通过 @Import注解引入一些Web容器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,// 引入一些对应的容器的类对象
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

	/**
	 * 这里注入了一个ServletWebServer的定制工厂
	 * @param serverProperties
	 * @return
	 */
	@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);
	}

	/**
	 * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
	 * {@link ImportBeanDefinitionRegistrar} for early registration.
	 */
	public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

		private ConfigurableListableBeanFactory beanFactory;

		@Override
		public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
			if (beanFactory instanceof ConfigurableListableBeanFactory) {
				this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
			}
		}

		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
			if (this.beanFactory == null) {
				return;
			}
			// 向容器中注册了一个后置处理器
			registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class);
			registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
					ErrorPageRegistrarBeanPostProcessor.class);
		}

		private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
			if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
				RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
				beanDefinition.setSynthetic(true);
				registry.registerBeanDefinition(name, beanDefinition);
			}
		}

	}

}

初始化和启动 tomcat

在ioc容器刷新时候,进行自定义拓展,实现tomcat的创建。

	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start reactive web server", ex);
		}
	}

	// tomcat执行
	private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			ServletWebServerFactory factory = getWebServerFactory();// 获取WebServer的工厂对象
			this.webServer = factory.getWebServer(getSelfInitializer()); // 获取具体的WebServer
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}

	// 获取tomcat工厂  调用getBean会进行初始化、实例化操作
	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);
	}

创建tomcat对象

	public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		Tomcat tomcat = new Tomcat();// 创建Tomcat容器,并且配置连接器,引擎等属性
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);// 创建连接器
		connector.setThrowOnFailure(true);
		// 给service添加connector
		tomcat.getService().addConnector(connector);
		// 定制自己的连接器
		customizeConnector(connector);
		// 设置到tomcat中
		tomcat.setConnector(connector);
		// 自动部署 false
		tomcat.getHost().setAutoDeploy(false);
		configureEngine(tomcat.getEngine()); // 配置Engine
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);// Service关联Connector
		}
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat); // 获取TomcatWebServer
	}

	public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
		Assert.notNull(tomcat, "Tomcat Server must not be null");
		this.tomcat = tomcat;
		this.autoStart = autoStart;
		initialize(); // 非常重要的初始化方法 ⭐️
	}

	// 启动Tomcat通过发布事件触发一些Listener的初始化  也只是完成tomcat的初始化工作
	this.tomcat.start();

	// 启动tomcat
	protected void finishRefresh() {
		super.finishRefresh();
		WebServer webServer = startWebServer();
		if (webServer != null) {
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1902453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue2 data内对象引用另一个data对象无法使用this的解决办法

背景&#xff1a;data内有一复杂对象&#xff0c;并且内部一属性经常修改&#xff0c;每次修改的话属性.属性会很长&#xff0c;所以希望引用另一简单对象&#xff0c;但data内this用不了。(集合数组是地址引用&#xff0c;基本数据类型这么操作没意义) 如&#xff1a; 解决办法…

【人工智能】-- 智能机器人

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;机器人介绍 &#x1f348;机器人硬件 &#x1f34d;机械结构 &#x1f34d;传感器 &#x1f34d;控…

2024年江苏省研究生数学建模科研创新实践大赛C题气象数据高精度融合技术研究论文和代码分析

经过不懈的努力&#xff0c; 2024年江苏省研究生数学建模科研创新实践大赛C题气象数据高精度融合技术研究论文和代码已完成&#xff0c;代码为C题全部问题的代码&#xff0c;论文包括摘要、问题重述、问题分析、模型假设、符号说明、模型的建立和求解&#xff08;问题1模型的建…

高效管理个人日程,智慧校园行政办公全指南

在智慧校园的行政办公体系里&#xff0c;个人日程管理功能担当起协调与优化每位教职员工日常安排的角色&#xff0c;它像一位贴心的时间助理&#xff0c;确保工作与私人生活的和谐并进。这一功能设计得既直观又灵活&#xff0c;让使用者能以自己偏好的视角审视时间规划&#xf…

Gradient Descent

在整个maching learning的第三个步骤要找一个最好的function。在第二步是定义了一个 Loss function L&#xff0c;这个L是一个function的fuction 求完偏微分之后得到的向量就是Gradient&#xff08;黄色部分&#xff09; 随机找一个起始点0&#xff0c;它的等高线的法线方向就…

绝区壹--LLM的构建模块

前言 语言是人类交流的本质&#xff0c;大型语言模型 (LLM) 凭借其出色的理解和生成类似人类的文本的能力&#xff0c;彻底改变了我们与语言互动和利用语言的方式。深入研究 LLM 的构建块&#xff08;向量、标记和嵌入&#xff09;&#xff0c;揭示了使这些模型能够以前所未有…

Nginx的安装与配置 —— Linux系统

一、Nginx 简介 1.1 什么是 Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx的并发能力在同类型的网页服务…

layui-表单(输入框)

1.基本使用方法 先写一个表单元素块 form 加上layui-form 里面写行区块结构&#xff0c;如下&#xff1a; 2.输入框选项 placeholder默认文本 autocomplete自动填充 lay-verify required必填

如何监控和分析 PostgreSQL 中的查询执行计划?

文章目录 一、为什么监控和分析查询执行计划很重要二、PostgreSQL 中用于获取查询执行计划的方法三、理解查询执行计划的关键元素四、通过示例分析查询执行计划五、优化查询执行计划的常见策略六、使用工具辅助分析七、结合实际案例的详细分析八、总结 在 PostgreSQL 数据库中&…

vb.netcad二开自学笔记5:ActiveX链接CAD的.net写法

一、必不可少的对象引用 使用activex需要在项目属性中勾选以下两个引用&#xff0c;若找不到&#xff0c;则浏览定位直接添加下面两个文件&#xff0c;可以看到位于cad的安装路径下&#xff0c;图中的3个mgd.dll也可以勾选。 C:\Program Files\Autodesk\AutoCAD 2024\Autodes…

上万组风电,光伏,用户负荷数据分享

上万组风电&#xff0c;光伏&#xff0c;用户负荷数据分享 可用于风光负荷预测等研究 获取链接&#x1f517; https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取码&#xff1a;381i 获取链接&#x1f517; https://pan.baidu.com/s/1izpymx6R3Y8JsFdx42rL0A 提取…

Python统计实战:时间序列分析之二阶曲线预测和三阶曲线预测

为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能&#xff0c;从而更快地掌握解决问题所需的能力。 &#xff08;以下练习题来源于《统计学—基于Python》。请在Q群455547227下载原始数据。&#xff09; 练习题 下表是某只股票…

Leetcode - 周赛404

目录 一&#xff0c;3200. 三角形的最大高度 二&#xff0c;3201. 找出有效子序列的最大长度 I 三&#xff0c;3202. 找出有效子序列的最大长度 II 四&#xff0c;3203. 合并两棵树后的最小直径 一&#xff0c;3200. 三角形的最大高度 本题直接模拟&#xff0c;分别计算一下…

KVM使用命令行添加新磁盘(注:支持热插拔)

1、使用qemu-img创建格式为qcow2的磁盘 [rootkvm ~]# qemu-img create -f qcow2 /var/lib/libvirt/images/test-disk.qcow2 15G 2、显示虚拟机硬盘列表&#xff0c;查看未使用的target [rootkvm ~]# virsh domblklist kvm-client 3、添加硬盘到kvm-client虚拟机中 [rootkvm…

Matlab2023a保姆级安装教程,附下载安装包资料

安装包放在前面&#xff01; 「MATLAB安装包 获取链接&#xff1a;https://pan.quark.cn/s/d8abf7394b3e 温馨提示:路径中不要有中文&#xff01;&#xff01; 1、下载全部的安装包&#xff0c;然后解压得到安装文件 2、解压之后可以看到包含Matlab R2023a安装光驱文件及Cr…

【Linux进阶】文件系统5——ext2文件系统(inode)

1.再谈inode (1) 理解inode&#xff0c;要从文件储存说起。 文件储存在硬盘上&#xff0c;硬盘的最小存储单位叫做"扇区"&#xff08;Sector&#xff09;。每个扇区储存512字节&#xff08;相当于0.5KB&#xff09;。操作系统读取硬盘的时候&#xff0c;不会一个个…

低负载高效率(轻载高效)的BUCK是如何实现的?

-----本文简介----- 主要内容包括&#xff1a; 轻载高效BUCK是何原理&#xff1f; ----- 正文 ----- 先赞↓后看&#xff0c;养成习惯&#xff01; 一、 DC-DC的控制模式与效率 1. PWM模式 如下图是PWM控制模式的DC-DC&#xff0c;PWM(Pulse Width Modulation)&#x…

昇思25天学习打卡营第11天|MindSpore 助力下的 GPT2:数据集加载处理及模型全攻略

目录 环境配置 数据集下载和获取 数据集拆分 处理数据集 模型构建 ​​​​​​​模型训练 ​​​​​​​模型推理 环境配置 “%%capture captured_output”这一行指令通常旨在捕获后续整个代码块所产生的输出结果。首先&#xff0c;将已预装的 mindspore 库予以卸载。随后&a…

奇迹MU 骷髅战士在哪

BOSS分布图介绍 我为大家带来各地区怪物分布图。在游戏前期&#xff0c;很多玩家可能会不知道该去哪里寻找怪物&#xff0c;也不知道哪些怪物值得打。如果选择了太强的怪物&#xff0c;弱小的玩家可能会无法抵御攻击。如果选择了低等级的boss&#xff0c;收益可能并不理想。所…

创建一个不带框架的javaweb工程

点击新建 选择Maven&#xff0c;然后在Archetype里面选择 webapp选项&#xff08;注意这里需要配置好Maven的环境 如果没配好Maven引入依赖的时候会引不进来&#xff09; 如果Maven配置之后就会显示配置成功 然后我们要配置tomacat的依赖 jde选择默认 然后点击部署 选择工件&a…