当前位置: 首页 > news >正文

springmvc源码流程解析(一)

       Springmvc 是基于servlet 规范来完成的一个请求响应模块,也是spring 中比较大的一个 模块,现在基本上都是零xml 配置了,采用的是约定大于配置的方式,所以我们的springmvc 也是采用这种零xml 配置的方式。

       要完成这种过程,要解决两个问题:1、取代web.xml 配置 ,2、取代springmvc.xml 配置。 取代web.xml 配置在servlet 中有一个规范,就是当servlet 容器启动的时候会根据SPI 规范加载 META-INF/services 文件夹下面的javax.servlet.ServletContainerInitializer 文件,该文件下面的 类会实现javax.servlet.ServletContainerInitializer 接口。

       SPI 也被称为服务接口扩展,(Service Provider Interface) 直译服务提供商接口, 不要被这个名字唬到了, 其实很好理解的一个东西: 就是根据Servlet厂商(服务提供商)提供要求的一个接口, 在固定的目录 (META-INF/services)放上以接口全类名 为命名的文件, 文件中放入接口的实现的 全类名,该类由我们自己实现,按照这种约定的方式(即SPI规范),服务提供商会 调用文件中实现类的方法, 从而完成扩展。

       该类SpringServletContainerInitializer在启动的时候会被servlet 容器(例如tomcat)实例化,然后调用onStartup 方法,并且servlet 容器会收集实现了@HandlesTypes 注解里面的接口的类(WebApplicationInitializer),并且做为入参传入到onStartup 方法中,我们拿到set 容器中的类就可以反射调用接口里面的方法了,这是servlet 规范,该规范就能保证servlet 容器在启动的时候就会完成这些操作。Springmvc 就借助这一点完成了取代web.xml 的工作。

我们定义了一个类MyWebAppInitializer继承自AbstractAnnotationConfigDispatcherServletInitializer,最上层的接口其实就是WebApplicationInitializer,这个接口有两个重要实现getRootConfigClasses将RootConfig引入了进来,这个RootConfig就是父容器的配置类,相当于之前的spring.xml;另一个方法getServletConfigClasses引入进来了WebAppConfig,这个是是子容器的配置类,相当于之前的spring-mvc.xml。

父容器会对com.dsk下的包进行扫描,但是排除了类上注解为@RestController和@Controller的类。因为controller要交给springmvc自身的子容器去管理,父容器会管理一些@Service相关的类。

子容器会对com.dsk下的包进行扫描,但是只扫描了类上注解为@RestContrller和@Controller的类

相关的类介绍完之后,看下核心的onStartup方法,我们定义的MyWebAppInitializer与其父类的继承关系分别是MyWebAppInitializer-》AbstractAnnotationConfigDispatcherServletInitializer-》AbstractDispatcherServletInitializer-》AbstractContextLoaderInitializer-》WebApplicationInitializer

第一步继续会调用父类的onStartUp方法

第二步注册dispatcherServlet

我们再往下一层AbstractContextLoaderInitializer父类的onStartup方法,可以看到这一步就是注册监听器ContextLoaderListener,注册进servletContext,这个监听器的作用其实就是当servlet容器(例如tomcat)启动成功后,会调用监听器的contextInitialized方法。

这一步相当于在web.xml中配置了ContextLoaderListener,如下

registerContextLoaderListener方法中不只是注册了listener,还创建了父容器rootAppContext

创建父容器的方法createRootApplicationContext中,其实就是熟悉的AnnotationConfigWebApplicationContext,他将父容器也就是RootConfig注册进了BeanDefinitionRegistry中

总结registerContextLoaderListener方法做了两件事情

1、创建父容器,也就是spring的AnnotationConfigWebApplicationContext

2、将ContextLoaderListener加入到servletContet中,注意此时ContextLoaderListener持有父容器对象rootContext方法,目的是当servlet容器启动成功后,会通知到监听器,此时监听器会调用父容器的refresh方法,将类注入到spring容器中。

那么父类AbstractContextLoaderInitializer的onStartUp方法就看完了,回到AbstractDispatcherServletInitializer类

这一步就是将dispatcherServlet注册进servletContext中,并把上下文对象设置到了
dispatcherServlet 对象中,相当于web.xml的如下配置

这个方法registerDispacherServlet不止是将dispatcherServlet加入到了servletContext,同时也创建了子容器,可以看到这个子容器也是AnnotationConfigWebApplicationContext,只不过此时注册进来的类是WebAppConfig,子类会将带有@Controller的类扫描进来,注入到子容器中。

那么onStartUp方法就执行完了,做个总结:

一、registerContextLoaderListener(servletContext);

做了两件事情1、创建父容器,且listener中持有父容器对象;2、将ContextLoaderListener加入到ServletContext

二、registerDispatcherServlet(servletContext);

做了两件事情1、创建子容器,且dispatcherServlet中持有子容器对象;2、将DispatcherServlet加入到ServletContext;

ContextLoaderListener启动:

执行完onStartUp方法后,此时父容器和子容器还没有启动,因为并没有执行到他们的refresh方法,我们知道当servlet容器(tomcat启动成功后)会调用监听器ContextLoaderListener.contextInitialized方法,这里会启动spring容器,把spring上下文对象放入到了servletContext中

DispatcherServlet 的启动:

了解DispatcherServlet的生命周期的会知道,DispatcherServlet启动过程中会执行init()方法,在这里会进行springmvc子容器的启动

这里会从servletContext中获取父容器对象,并将子容器webApplicationContext的parent赋值为rootContext,然后执行子容器的refresh()方法。

在调用子容器的刷新方法前,这里会注册一个监听器(该监听会初始化springmvc所需信息),
ContextRefreshedEvent可以看到该监听器监听的是容器refreshed事件, 会在子容器的refresh方法中的finishRefresh中发布,这是spring的监听器模式。

子容器的refresh()方法最后一步,会发布事件触发监听器的执行

这里面的每一个方法不用太细看, 就是给SpringMVC准备初始化的数据, 为后续SpringMVC处理请求做准备基本都是从容器中拿到已经配置的Bean(RequestMappingHandlerMapping、
RequestMappingHandlerAdapter、HandlerExceptionResolver )放到dispatcherServlet中做准备。但是这些Bean又是从哪来的呢?? 回到我们的WebAppConfig使用的@EnableWebMvc,也就是这个注解取代了springmvc.xml


1. 导入了DelegatingWebMvcConfiguration@Import(DelegatingWebMvcConfiguration.class)
2. DelegatingWebMvcConfiguration的父类就配置了这些Bean
3. SpringBoot也是用的这种方式;

总结:
1. Tomcat在启动时会通过SPI注册 ContextLoaderListener和DispatcherServlet对象
a. 同时创建父子容器
i. 分别创建在ContextLoaderListener初始化时创建父容器设置配置类
ii. 在DispatcherServlet初始化时创建子容器设置配置类
2. Tomcat在启动时执行ContextLoaderListener和DispatcherServlet对象的初始化方
法, 执行容器refresh进行加载
3. 在子容器加载时 创建SpringMVC所需的Bean和预准备的数据:(通过配置类
@EnableWebMvc配置(DelegatingWebMvcConfiguration)——可实现WebMvcConfigurer进行定制扩展)
a. RequestMappingHandlerMapping,它会处理@RequestMapping 注解
b. RequestMappingHandlerAdapter,则是处理请求的适配器,确定调用哪个类的哪个方法,并且构造方法参数,返回值。
c. HandlerExceptionResolver 错误视图解析器
d. addDefaultHttpMessageConverters 添加默认的消息转换器(解析json、解析xml)等
4. 子容器需要注入父容器的Bean时(比如Controller中需要@Autowired例如Service的Bean); 会先从子容器中找,没找到会去父容器中找。

一、Spring和SpringMVC为什么需要父子容器?不要不行吗?就实现层面来说不用子父容器也可以完成所需功能(参考:SpringBoot就没用子父容器)?
1. 所以父子容器的主要作用应该是早期Spring为了划分框架边界。有点单一职责的味道service、dao层我们一般使用spring框架来管理、controller层交给springmvc管理
2. 规范整体架构 使 父容器service无法访问子容器controller、子容器controller可以访问父容器 service
3. 方便子容器的切换。如果现在我们想把web层从spring mvc替换成struts,那么只需要将springmvc.xml替换成Struts的配置文件struts.xml即可,而spring.xml不需要改变。
4. 为了节省重复bean创建
二、是否可以把所有Bean都通过Spring容器来管理?(Spring的applicationContext.xml中配置全局扫描)?
不可以,这样会导致我们请求接口的时候产生404。 如果所有的Bean都交给父容器,SpringMVC在初始化HandlerMethods的时候(initHandlerMethods)无法根据Controller的handler方法注册HandlerMethod,并没有去查找父容器的bean;也就无法根据请求URI 获取到 HandlerMethod来进行匹配.
三、是否可以把我们所需的Bean都放入Spring-mvc子容器里面来管理(springmvc的springservlet.xml中配置全局扫描)?
可以 , 因为父容器的体现无非是为了获取子容器不包含的bean, 如果全部包含在子容器完全用
不到父容器了, 所以是可以全部放在springmvc子容器来管理的。虽然可以这么做不过一般应该是不推荐这么去做的,一般人也不会这么干的。如果你的项目里有用到事物、或者aop记得也需要把这部分配置需要放到Spring-mvc子容器的配置文件来,不然一部分内容在子容器和一部分内容在父容器,可能就会导致你的事务或者AOP不生效。 所以如果aop或事务如果不生效也有可能是通过父容器中的类(spring)去增强子容器的类(Springmvc),也就无法增强。

下个章节我们解析springmvc的请求源码流程。

相关文章:

springmvc源码流程解析(一)

Springmvc 是基于servlet 规范来完成的一个请求响应模块,也是spring 中比较大的一个 模块,现在基本上都是零xml 配置了,采用的是约定大于配置的方式,所以我们的springmvc 也是采用这种零xml 配置的方式。 要完成这种过程&#xff…...

【论文阅读】SRGAN

学习资料 论文题目:基于生成对抗网络的照片级单幅图像超分辨率(Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network)论文地址:https://arxiv.org/abs/1609.04802代码:GitHub - xiph/daala: Modern video compression for the interne…...

kubelet PLEG实现

概述 kubelet的主要作用是确保pod状态和podspec保持一致,这里的pod状态包括pod中的container状态,个数等。 为了达到这个目的,kubelet需要从多个来源watch pod spec的变化,并周期从container runtime获取最新的container状态。比如…...

leetcode49:字母异位词分组

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", &…...

一个将.Geojson文件转成shapefile和kml文件的在线页面工具(续)

接上一专栏:这个网址有个bug,每个月只能免费转3次,这等于没用! 一个将.Geojson文件转成shapefile和kml文件的在线页面工具_geojson转shp在线-CSDN博客 下面这个网址实测可以免费多次转换! Quickmaptools : Geojson to…...

论文阅读(二十四):SA-Net: Shuffle Attention for Deep Convolutional Neural Networks

文章目录 Abstract1.Introduction2.Shuffle Attention3.Code 论文:SA-Net:Shuffle Attention for Deep Convolutional Neural Networks(SA-Net:置换注意力机制)   论文链接:SA-Net:Shuffle Attention for Deep Convo…...

基于YOLOv8深度学习的智能道路裂缝检测与分析系统【python源码+Pyqt5界面+数据集+训练代码】

背景及意义 智能道路裂缝检测与分析系统在基础设施维护和安全监测方面起着非常重要的作用。道路裂缝是道路衰老和破坏的早期迹象,若不及时发现和修复,可能会导致道路结构的进一步恶化,甚至引发安全事故。本文基于YOLOv8深度学习框架&#xff…...

YOLOv11入门到入土使用教程(含结构图)

一、简介 YOLOv11是Ultralytics公司在之前的YOLO版本上推出的最新一代实时目标检测器,支持目标检测、追踪、实力分割、图像分类和姿态估计等任务。官方代码:ultralytics/ultralytics:ultralytics YOLO11 🚀 (github.com)https://g…...

python 爬虫抓取百度热搜

实现思路: 第1步、在百度热搜页获取热搜元素 元素类名为category-wrap_iQLoo 即我们只需要获取类名category-wrap_为前缀的元素 第2步、编写python脚本实现爬虫 import requests from bs4 import BeautifulSoupurl https://top.baidu.com/board?tabrealtime he…...

3.1 > Linux文件管理(基础版)

Linux 的命名规则 相对于其他操作系统(如 Windows )来说,Linux 的命名规则并没有那么多条条框框,还算是比较自由的。在 Linux 中,它的命名规则有如下几点要求: 首先是大小写敏感:例如在 Linux…...

CTFHUB技能树之文件上传——MIME绕过

开启靶场&#xff0c;打开链接&#xff1a; 直接指明是MIME验证 新建04MIME.php文件&#xff0c;内容如下&#xff1a; <?php echo "Ciallo&#xff5e;(∠・ω< )⌒★";eval($_POST[pass]);?> &#xff08;这里加了点表情&#xff0c;加带点私货&#x…...

4种鼓励创业创新的方法

随着市场趋于饱和&#xff0c;许多企业&#xff0c;尤其是初创企业&#xff0c;很难在竞争中保持领先地位。技术为企业彻底改变其营销和管理策略铺平了道路。另一个经过实践检验的成功渗透特定市场的方法是在办公室内部激发创新&#xff0c;从员工到品牌皆如此。 那么究竟如何…...

C#中的LINQ之美:优雅的数据查询与操作

LINQ&#xff08;Language Integrated Query&#xff0c;语言集成查询&#xff09;是C#中一个强大的工具&#xff0c;它将查询功能直接融入到语言中&#xff0c;使开发者能够以一种更直观、更接近自然语言的方式来操作数据。LINQ不仅能极大地提高开发效率&#xff0c;而且让代码…...

深入浅出:深度学习模型部署全流程详解

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a; 【论文精读】PSAD&#xff1a;小样本部件分割揭示工业异常检测的合成逻辑每日一言&#x1f33c;: 生活要有所期待&#xff0c; 否则就如同罩在…...

git已经commit,但未push想撤回提交

git已经commit,但未push想撤回提交 1、重置到上一个提交2、只想撤回提交但保留修改3、操作方法 工作区(本地)、暂存区(commit)、版本库(远程) 1、重置到上一个提交 git reset --hard HEAD~1 这会将当前分支重置到上一个提交&#xff0c;丢弃你的最新提交和所有未保存的修改。 …...

SSL VPN调试思路及配置指南

一、概述 本指南旨在详细阐述外部人员通过SSL VPN访问内部资源的调试过程与配置步骤。SSL VPN被单臂部署在核心交换机上&#xff0c;并通过外网防火墙将SSL VPN的443端口映射至外部网络&#xff0c;以实现安全的远程访问。 二、配置步骤 系统管理 网络设置&#xff1a; 配置接…...

多租户架构的全景分析(基本概念、实现策略、资源管理和隔离、数据安全与隔离、性能优化、扩展性与升级、案例研究)

文章目录 1. 多租户的基本概念2. 多租户的实现策略2.1 独立数据库模式2.2 共享数据库-独立Schema模式2.3 共享数据库-共享Schema模式 3. 资源管理和隔离4. 数据安全与隔离5. 性能优化6. 扩展性与升级7. 案例研究总结 多租户架构在云计算和SaaS应用中越来越流行&#xff0c;因为…...

TDengine数据库整合MyBatis实现SpringBoot项目CRUD

TDengine数据库整合MyBatis实现SpringBoot项目CRUD 官网&#xff1a; https://docs.taosdata.com/引入依赖 <!-- mybatis版本必须与druid版本兼容&#xff0c;否则无法创建DataSource --><dependency><groupId>com.alibaba</groupId><artifactId&…...

1493. 删除一个元素以后全为1的最长子数组 - 题解

> Problem: 1493. 删掉一个元素以后全为 1 的最长子数组 1493. 删除一个元素以后全为1的最长子数组 - 题解 问题描述 给定一个二进制数组 nums&#xff0c;你需要从中删除一个元素。请你在删掉元素后返回最长的且只包含 1 的非空子数组的长度。如果不存在这样的子数组&…...

密钥管理方法DUKPT的OpenSSL代码实现Demo

目录 1 DUKPT简介 2 基本概念 2.1 BDK 2.2 KSN 2.3 IPEK 2.4 FK 2.5 TK 3 工作流程 3.1 密钥注入过程 3.2 交易过程 3.3 BDK派生IPEK过程 3.4 IPEK计算FK过程 4 演示Demo 4.1 开发环境 4.2 功能介绍 4.3 下载地址 5 在线工具 6 标准下载 1 DUKPT简介 DUKPT&a…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

实战三:开发网页端界面完成黑白视频转为彩色视频

​一、需求描述 设计一个简单的视频上色应用&#xff0c;用户可以通过网页界面上传黑白视频&#xff0c;系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观&#xff0c;不需要了解技术细节。 效果图 ​二、实现思路 总体思路&#xff1a; 用户通过Gradio界面上…...