深入源码解析:Spring Boot 如何加载 Servlet 、Filter 与 Listener
我们知道,Spring Boot 是在 Spring MVC 的基础上进行了封装,以简化开发者的工作量。尽管如此,Spring Boot 的底层架构依然离不开 Spring MVC 的核心组件,如 Servlet、Filter、Listener,以及RequestMappingHandlerMapping 和RequestMappingHandlerAdapter等。
在传统的 Spring MVC项目中,我们可以通过web.xml文件、注解的方式,或通过 SPI 扩展机制来配置和初始化这些关键组件。然而,在 Spring Boot 项目中,我们默认是没有做这些操作的,那么其又是如何初始化这些关键组件呢?本帖我们着重探究Servlet、Filter、Listener。
再探究Servlet、Filter、Listener初始化的过程前,我们需要了解两个概念,Web容器和Spring IOC容器,二者不是同一个概念。
Web 容器(也称为 Servlet 容器)是用于处理 Web 应用程序的服务器环境。它负责管理 Web 应用程序的生命周期,并提供必要的服务来处理 HTTP 请求和响应,常见的 Web 容器有 Apache Tomcat、Jetty等。注意我们的Servlet、Filter、Listener组件就是存储在该容器中。
Spring IOC 容器(Inversion of Control 容器)是 Spring 框架的核心部分,它负责管理 Java bean 对象的生命周期和依赖关系。
从上面可以看出,Servlet、Filter、Listener的初始化离不开Web容器,而我们常用的就是Tomcat,再Spring Mvc中我们采用的外置Tomcat,但是再Spring Boot中采用了内置Tomcat,二者大同小异,所以再研究Spring Boot内置Tomcat如何初始化Servlet、Filter、Listener组件前,我们需要先大体了解一下Spring MVC外置Tomcat 如何加载这三个组件。
1.外置Tomcat
外置Tomcat典型应用就是Spring MVC项目。首先我们需要先了解一下Tomcat的整体架构,如下图:
注意:Spring IOC容器的创建是在上图中Context组件中执行servlert.init方法进行创建的,而Tomcat启动Spring MVC项目的时候,会按照server->service->Engine->host->context->wrapper(默认DispatcherServlet)的顺序进行对象的实例化,那么很明显我们的servlet是再Spring IOC容器创建之前就已经创建了,因此Spring IOC无法存储管理这些组件,所以用Web容器来存储管理这些组件。
再外置Tomcat中,整个项目启动的时候会创建context实例(对应一个项目),而context实例的实现类为StandardContext,该类实现了Lifecycle接口,因此具有生命周期,再其生命周期中存在12中状态,每种状态均会发布不同的事件,其有一个非常重要的监听器即ContextConfig,该监听器针对context组件再不同的生命阶段发布的不同事件进行监听处理,其中就包括我们项目中web.xml的解析,这样就会帮我们创建三大组件,然后绑定到context组件中的属性中。如下图:
通过上面流程,可以看出Servlet、Filter、Listener组件需要存储在Web容器中,且要和Tomcat中的context组件绑定对应的关系。
但是再Spring Boot项目中,我们是通过内嵌Tomcat来实现项目的加载,而内嵌Tomcat的实现是再Spring源码中的refresh()方法中的onRefresh()方法来具体实现的,再执行onRefresh()方法之前Spring IOC容器就已经创建完成了,那么Spring Boot是如何实例化Servlet、Filter、Listener组件以及又是如何将这三个组件跟Web容器中的Context组件绑定关系呢?
2.内置Tomcat
内置Tomcat的典型应用就是Spring Boot项目,而从Spring Boot的源码中可以看出,内嵌Tomcat的实现是在ServletWebServerApplicationContext中的onRefresh() 方法,但是该方法的调用比较靠后,此时Spring IOC容器已经创建而Web容器还未创建,那么Spring Boot项目是如何创建Servlet、Filter、Listener组件,又是如何将三大组件跟Web容器中的context绑定关系。
1.Spring Boot项目是如何创建Servlet、Filter、Listener
Spring Boot再创建Servlet、Filter、Listener组件时原理相同,此处我们以Servlet为主进行介绍。Servlert的创建离不开Spring Boot的自动装配,而WebMvcAutoConfiguration自动配置类就显的比较重要,如下图:
其会帮我们导入一个DispatcherServletAutoConfiguration,而该类则是DispatcherServlet创建的重中之重,如下图:
经过上面Spring Boot的自动装配,默认的Servlet就已经注入到IOC容器中。
2.Spring Boot IOC容器中的servlet如何跟Web容器中的context绑定关系
该过程是在内嵌Tomcat启动的过程中进行的,即Spring源码中的onRefresh() 方法中进行的。该流程的实现离不开一个关键类,即TomcatStarter,它实现了ServletContainerInitializer接口(jakarta.servlet),上面的DispatcherServletRegistrationBean也实现了ServletContainerInitializer接口(org.springframework.boot.web.servlet)。注意:两者只是名称相同,全类限定名不同哈。
我们需要先看一下内嵌Tomcat是如何启动的,关键是ServletWebServerApplicationContext.createWebServer()方法,如下图:
而真正实现Servlet与context组件绑定父子关系的是getWebServer(getSelfInitializer())方法的参数getSelfInitializer()方法,该方法是一个lambda,具体如下:
我们接着看一下getWebServer方法,看看TomcatStart,如何被设置,如何被调用:
接着看一下configureContext(context, initializersToUse)方法,如下:
那么TomcatStarter又是何时被调用的,前面也说到了context的声明周期中存在多种状态,当该组件start的时候,会调用TomcatStarter,如下图:
接下来看一下TomcatStarter,如下图:
所以再调用TomcatStarter.onStartup方法的时候就相当于调用我们的lambda,接下来看一下lambda,如下图:
而我们再自动配置类定义的DispatcherServletRegistrationBean就是实现了org.springframework.boot.web.servlet.ServletContextInitializer,所以此处可以拿到。
我们进一步按一下getServletContextInitializerBeans()方法,如下图:
至此我们会调用关键类的DispatcherServletRegistrationBean.onStartup方法,来将封装在里面的DispatcherServlet跟context组件绑定父子关系,如下图:
接着继续看一下register方法:如下图:
接着继续看一下addRegistration方法:如下图:
至此,Servlet、Filter、Listener组件就绑定到Tomcat中的context组件上,context组件start方法的后续就会调用三大组件的init方法:
如果您希望更深入地学习SpringBoot源码,我强烈推荐您访问以下项目链接:https://gitee.com/chengyadong555/spring-boot.git 。在这个项目中,您将发现对SpringBoot源码的逐行分析,作者不仅提供了丰富的注释,还融入了自己独到的理解和见解。
相关文章:
深入源码解析:Spring Boot 如何加载 Servlet 、Filter 与 Listener
我们知道,Spring Boot 是在 Spring MVC 的基础上进行了封装,以简化开发者的工作量。尽管如此,Spring Boot 的底层架构依然离不开 Spring MVC 的核心组件,如 Servlet、Filter、Listener,以及RequestMappingHandlerMappi…...
Vue 让视图区域滑到指定位置、回到顶部
滑倒指定位置:获取指定的dom,然后用scrollIntoView使dom出现在视图区域 回到顶部:操作父级dom的scrollTop 0,让该父级下的列表回到顶部 代码如下 <template><div class"testDemo"><div><el-bu…...
C# 属性(Property)
C# 属性(Property) C# 中的属性(Property)是一种用于访问和设置类或结构成员的值的特殊类型的方法。属性允许开发者以字段的形式访问方法,提供了更为安全和灵活的数据封装。在本文中,我们将深入探讨 C# 属性的概念、用途、以及如何有效地使用它们。 属性的定义 属性由…...
Ubuntu20.04调整swap分区大小笔记
Ubuntu20.04调整swap分区大小笔记 参考:https://blog.csdn.net/sunyuhua_keyboard/article/details/142485764 第一步 禁用swap $ cat /etc/fstab # /etc/fstab: static file system information. # # Use blkid to print the universally unique identifier fo…...
【 JAVA中常见的集合操作】
JAVA中常见的集合操作 Java 提供了丰富的集合框架(Java Collections Framework),包括多种集合接口和实现类。集合操作可以分为基本操作和高级操作。下面介绍一些常见的集合操作,并给出相应的代码示例。 基本集合操作 创建集合 …...
Kudu 源码编译-aarch架构 1.17.1版本
跟着官方文档编译 第一个问题:在make阶段时会报的问题: kudu/src/kudu/util/block_bloom_filter.cc:210:3: error: ‘vst1q_u32_x2’ was not declared in this scope kudu/src/kudu/util/block_bloom_filter.cc:436:5: error: ‘vst1q_u8_x2’ was no…...
JavaEE多线程案例之阻塞队列
上文我们了解了多线程案例中的单例模式,此文我们来探讨多线程案例之阻塞队列吧 1. 阻塞队列是什么? 阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则. 阻塞队列是⼀种线程安全的数据结构,并且具有以下特性: 当队列满的时候,继续⼊队列就会…...
Java Web 开发学习中:过滤器与 Ajax 异步请求
一、过滤器 Filter: 过滤器的概念与用途 在一个庞大的 Web 应用中,有许多资源需要受到保护或进行特定的预处理。过滤器就像是一位智能的守卫,站在资源的入口处,根据预先设定的规则,决定哪些请求可以顺利访问资源&…...
git SSL certificate problem: unable to get local issuer certificate
Git 客户端将会验证服务器端提供的SSL证书是否由受信任的证书颁发机构(Certification Authority,CA)签发。如果Git客户端无法找到或验证本地签发者证书,就会出现 unable to get local issuer certificate 或类似的错误。 该问题一…...
Vue.js 响应接口
Vue.js 响应接口 Vue.js,作为一个流行的前端JavaScript框架,以其响应式数据绑定和组件化开发而闻名。响应式系统是Vue.js的核心特性之一,它允许开发者创建高度动态和交互式的用户界面。本文将深入探讨Vue.js的响应接口,包括其工作原理、使用方法和最佳实践。 响应式原理 …...
vue2-代理打包问题;CORS针对AJAX 请求,而不适用于资源请求
打包后请求被转发出现问题(如返回 405 Method Not Allowed),通常是由以下原因导致的: 1. 代理配置未生效 原因分析 在开发环境中,Vue CLI 的 devServer.proxy 仅在本地开发服务器(npm run serveÿ…...
websocket 服务 pinia 全局配置
websocket 方法类 // stores/webSocketStore.ts import { defineStore } from "pinia";interface WebSocketStoreState {ws: WebSocket | null; // WebSocket 实例callbacks: ((message: string) > void)[]; // 消息回调函数列表connected: boolean; // 连接状态…...
YOLO系列正传(二)YOLOv3论文精解(上)——从FPN到darknet-53
系列文章 YOLO系列基础 YOLO系列基础合集——小白也看得懂的论文精解-CSDN博客 YOLO系列正传 YOLO系列正传系列(一)类别损失与MSE损失函数、交叉熵损失函数-CSDN博客 背景 随着YOLOv11版本的发布,YOLO算法在视觉检测领域独领风骚&#x…...
可视化建模与UML《部署图实验报告》
一、实验目的: 1、熟悉部署图的基本功能和使用方法。 2、掌握使用建模工具软件绘制部署图的方法 二、实验环境: window11 EA15 三、实验内容: 根据以下的描述,绘制部署图。 网上选课系统在服务器端使用了两台主机,一…...
详解RabbitMQ在Ubuntu上的安装
目录 Ubuntu 环境安装 安装Erlang 查看Erlang版本 退出命令 编辑安装RabbitMQ 确认安装结果 安装RabbitMQ管理界面 启动服务 查看服务状态 通过IP:port访问 添加管理员用户 给用户添加权限 再次访问 Ubuntu 环境安装 安装Erlang RabbitMq需要…...
SQL 快速参考
SQL 快速参考 引言 SQL(Structured Query Language)是一种用于管理关系数据库管理系统(RDBMS)的标准编程语言。它被广泛用于数据查询、数据更新、数据库维护以及访问控制。本快速参考指南旨在提供SQL的基本概念和常用命令的概览…...
数据结构--树和二叉树
树和二叉树的定义 树的定义 树是一种非线性的数据结构,它模拟了具有层次关系的数据的集合。在树结构中,存在以下基本概念: 节点(Node):树的每个元素被称为节点。根节点(Root Node)…...
R语言的数据结构-向量
【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 在R语言中,数据结构是非常关键的部分,它提…...
MetaGPT源码 (ContextMixin 类)
目录 理解 ContextMixin什么是 ContextMixin?主要组件实现细节 测试 ContextMixin示例:ModelX1. 配置优先级2. 多继承3. 多继承重写4. 配置优先级 在本文中,我们将探索 ContextMixin 类,它在多重继承场景中的集成及其在 Python 配…...
linux中top命令详解
top 命令是 Linux 系统中常用的实时系统监控工具,它可以显示系统的实时进程和资源占用情况。以下是 top 命令的一些基本用法和参数详解: 基本用法 • top:运行 top 命令,显示系统实时监控信息。 • top -h:显示帮助信…...
Scrapy与MongoDB
Scrapy可以在非常短的时间里获取大量的数据。这些数据无论是直接保存为纯文本文件还是CSV文件,都是不可取的。爬取一个小时就可以让这些文件大到无法打开。这个时候,就需要使用数据库来保存数据了。 MongoDB由于其出色的性能,已经成为爬虫的首…...
【Linux-ubuntu通过USB传输程序点亮LED灯】
Linux-ubuntu通过USB传输程序点亮LED灯 一,初始化GPIO配置1.使能时钟2.其他寄存器配置 二,程序编译三,USB传输程序 一,初始化GPIO配置 1.使能时钟 使能就是一个控制信号,用于决定时钟信号是否能够有效的传递或者被使用,就像一个…...
onlyoffice 容器配置修改后制作镜像导出以及上传到 dockerhub
1.将容器制作成新的镜像 docker commit -p -a "xxx" -m "zh-cn-20-100" onlyoffice ooffice:7.1.1.23docker commit: 这是 Docker 中用于创建新镜像的命令。 -p: 这个选项用于在提交之前暂停容器的运行。这可以确保数据的完整性,因为容器在提交…...
开发者如何使用GCC提升开发效率 Windows下Cmake + NDK 交叉编译 Libyuv
最近在导入其他项目的libyuv库,编译时发现如下问题,刚好想做一期libyuv编译与安装到AS中的文章,故记录集成的全过程 报错如下 error: no member named ABGRToNV21 in namespace libyuv; did you mean ARGBToNV21? error: no member named …...
前端H5移动端基础框架模板 :Vue3 + Vite5 + Pinia + Vant4 + Sass + 附源码
技术栈选用 Vue3 Vite5 Pinia Vant4 Sass 源码地址: git clone https://gitee.com/gaiya001/h5-APP.git1. 1.vite.config.js文件配置 ** import { defineConfig } from vite // 导入 Vite 的配置函数 import vue from vitejs/plugin-vue // 导入 Vue 插件 i…...
华为HCIP H12-821考试中心原题题库更新完成 展示如下
全题库506题,后期有更新会及时更新维护,确保答案正确率和原题覆盖率。 附上最新通过成绩单一张 今天新鲜出炉 ...
SQL Server:只有MDF文件,如何附加数据库
第一步:先新建一个同名数据库,然后停止sql服务,删除新建数据库.ldf文件。 第二步:将要附加的数据库的.mdf文件覆盖刚新建的.mdf文件,并重启sql服务。 第三步:这时数据库DATA目录下只有一个.mdf文件…...
nginx反向代理(负载均衡)和tomcat介绍
nginx的代理 负载均衡 负载均衡的算法 负载均衡的架构 基于ip的七层代理 upstream模块要写在http模块中 七层代理的调用要写在location模块中 轮询 加权轮询 最小连接数 ip_Hash URL_HASH 基于域名的七层代理 配置主机 给其余客户机配置域名 给所有机器做域名映射 四层代理…...
【前端】-【前端文件操作与文件上传】-【前端接受后端传输文件指南】
目录 前端文件操作与文件上传前端接受后端传输文件指南前端excel、word操作指南 excelword 前端文件操作与文件上传 一、前端文件上传有两种思路: 二进制blob传输:典型案例是formData传输,相当于用formData搭载二进制的blob传给后端base…...
Android IO 性能优化:全面解析与实践
文章目录 前言1、文件系统与 I/O 流程原理1.1 文件系统架构1.2 文件 I/O 流程 2、优化策略与场景适用2.1 异步 I/O2.2 合并文件操作2.3 页缓存优化2.4 内存映射文件 3. 性能监控与验证总结 前言 在现代 Android 应用中,I/O 性能直接影响用户体验。流畅的响应速度和…...
利用Docker分层构建优化镜像大小
合适docker镜像文件大小不仅影响容器启动效率,也影响资源占用效率。本文介绍如何利用分层方式构建docker镜像,采用多种方式避免镜像文件太大而影响性能。 Docker 镜像大小优化的重要性 资源利用效率 较小的镜像文件在存储和传输过程中占用更少的空间和带…...
【代码pycharm】动手学深度学习v2-09 Softmax 回归 + 损失函数 + 图片分类数据集
课程链接 1.读取图像分类数据集 import matplotlib.pyplot as plt import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2l d2l.use_svg_display() #读取数据集 transtransforms.ToTensor() mnist_…...
docker开启远程访问
1、编辑docker.server文件 vi /usr/lib/systemd/system/docker.service 找到 [Service] 节点,修改 ExecStart 属性,增加 -H tcp://0.0.0.0:2375 ExecStart/usr/bin/dockerd -H fd:// --containerd/run/containerd/containerd.sock -H tcp://0.0.0.0:2…...
Maven插件打包发布远程Docker镜像
dockerfile-maven-plugin插件的介绍 dockerfile-maven-plugin目前这款插件非常成熟,它集成了Maven和Docker,该插件的官方文档地址如下: 地址:https://github.com/spotify/dockerfile-maven 其他说明: dockerfile是用…...
基于STM32的太阳跟踪系统设计
目录 引言系统设计 硬件设计软件设计系统功能模块 太阳位置检测模块伺服驱动控制模块反馈调整模块电源管理模块控制算法 太阳位置估算算法跟踪调整算法代码实现 太阳位置检测与估算伺服电机控制系统反馈与调整系统调试与优化结论与展望 1. 引言 太阳能是一种清洁、可再生的能…...
004-Redis 持久化
Redis 持久化 一、RDB 持久化1.优点:2.缺点:3.实现方式: 二、AOF 持久化1.优点:2.缺点:3.实现方式:4.重写机制5.重写流程: Redis 提供了两种主要的持久化方式:RDB 和 AOF 一、RDB 持…...
类OCSP靶场-Kioptrix系列-Kioptrix Level 1
一、前情提要 Kioptrix Level是免费靶场,可以自己百度下载。 开始前要先将靶机设置和kali同一个网络模式,我这里设置的是NAT。 接下来的靶机用kali进行演示。 二、打靶演示 这个靶机练习,相当于内网渗透。 1. 信息收集 1.1. 主机发现 …...
短视频矩阵系统功能介绍与独立部署流程
一、短视频矩阵系统功能介绍 短视频矩阵系统,作为当前短视频运营的重要工具,凭借其强大的功能,为内容创作者和企业提供了高效、便捷的短视频管理与运营方案。以下是对该系统核心功能的详细介绍: 多平台账号管理ÿ…...
【AI知识】人工智能、机器学习、深度学习的概念与联系
下图来自博客 机器学习和深度学习概念入门 ,图中可明显看到人工智能、机器学习、深度学习三个概念的包含关系,下面简单介绍一下这三个概念已经它们之间的联系。 1. 人工智能(Artificial Intelligence,AI) 概念&#x…...
今天你学C++了吗?——C++中的类与对象(日期类的实现)——实践与知识的碰撞❤
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
一个简单带颜色的Map
越简单 越实用。越少设计,越易懂。 需求背景: 创建方法,声明一个hashset, 元素为 {“#DE3200”, “#FA8C00”, “#027B00”, “#27B600”, “#5EB600”} 。 对应的key为 key1 、key2、key3、key4、key5。 封装该方法,…...
前端工程化(三)
如何使用 Webpack 优化产出代码? 使用 Webpack 优化产出代码可以通过以下几种方式: 压缩代码:在生产环境中,使用 UglifyJSPlugin 或 TerserPlugin 等插件对代码进行压缩,可以减少代码体积,提高加载速度。…...
SQLAlchemy: Python中的强大数据库工具
SQLAlchemy: Python中的强大数据库工具 SQLAlchemy是一个功能强大的Python库,广泛应用于数据库操作。它提供了一个灵活的数据库抽象层,可以帮助开发者轻松与关系型数据库进行交互。本文将介绍SQLAlchemy的核心组件、常用功能以及它的优势。 1. SQLAlch…...
scala的泛型特质的应用场景
//泛型特质的应用场景 //作比较找出最大值 //定义一个函数,用来求List元素中的最大值参考代码:object Test4 {def getMax[T](list:List[T])(implicit ev:T > Ordered[T]): T {list.reduce((a:T,b:T)> if(a>b) a else b)}def main(args: Array…...
【C++】重载运算与类型转换(七):成员访问运算符
14.7 成员访问运算符 在迭代器类和智能指针类常常用到解引用运算符(*)和箭头运算符(->)。以如下形式向 StrBlobPtr 类添加这两种运算符: class StrBlobPtr {public:std::string& operator*() const{ auto p …...
论文结论:GPTs and Hallucination Why do large language models hallucinate
GPTs and Hallucination 当一个主题有普遍共识,并且有大量语言可用于训练模型时,大模型的输出可以反映出该共识观点在没有足够关于主题的语言示例【晦涩/数据有限】,或者主题有争议,或是对主题没有明确共识的情况下,就…...
修改通过 Docker 部署的 WordPress 上传文件的大小
要修改通过 Docker 部署的 WordPress 上传文件的大小,你可以按照以下步骤操作: 进入 Docker 容器:首先,你需要进入 WordPress 容器内部。可以使用如下命令: docker exec -it wordpress /bin/bash其中wordpress是你的 W…...
微信小程序:实现节点进度条的效果;正在完成的节点有动态循环效果;横向,纵向排列
参考说明 微信小程序实现流程进度功能 - 知乎 上面的为一个节点进度条的例子,但并不完整,根据上述代码,进行修改完善,实现其效果 横向效果 代码 wxml <view classorder_process><view classprocess_wrap wx:for&quo…...
信而泰网络测试仪校准解决方案
一、影响仪表精度的因素 网络测试仪是用于对数据网络及其相关设备性能参数进行测试的仪表,可以模拟网络终端产生流量,进行网络性能测试,对网络状态进行实时监测,分析和统计。数字计量对于精准数据的网络测试仪来说是一剂强心针&a…...
聊聊在应用层面实现内网穿透功能是否可行
前言 最近接手了供方开发的网关项目,交接文档里面有个内网穿透的功能,一下子就吸引的我的目光。实现这个内网穿透的背景是业务部门有些业务是部署在公网,这些公网的业务想访问内网的业务,但因为公网和内网没打通,导致…...