从上帝视角认识SpringMVC预览

news2025/4/18 20:44:03

前言

SpringMVC提供了很多可拓展的组件,例如:参数解析器、拦截器、异常处理器等等。但是如果想要理解/找到这些组件工作的位置/时机,很多时候总是容易迷失在其层层调用的源码之中。因此才想从上帝视角来剖析它。而所谓上帝视角,就是回到SpringMVC的设计本身,来理解他。

DispatcherServlet

相信大家都认识这东西,作用啥的也就不多说了。但请先暂时记住这一点: 他是javax.servlet.Servlet。

环境准备

WebApplicationContext

什么是上下文

还记得以前做阅读理解题目的时候吗?老师经常说的一句话是:联系上下文。又比如,你跟淘宝客服聊天,有时候我们总是先把商品发给对方,然后再说这个有没有其他颜色之类的。而这些推动事情继续发展的“背景知识”就可以叫做上下文。
回到Spring,像环境配置、bean对象在哪里、事件发布等等,都属于上下文信息。即使,不是直接的进行参与,至少也要能够“联系”到对应的人来处理。例如,BeanFactory。如果从这个角度看的话,还能这样理解,他就是一个信息机构,有点像情报机构。你想要的东西他都能给你找来。实际上,我们在工作中,临时接入某个事情的时候,都需要进行交接/学习“上下文”。在了解事情的背景知识之后,我们才能进一步开展工作。
在这里插入图片描述
不过,由于Spring的上下文,是整个应用运行的上下文,因此Spring的上下文需要具备的背景知识比较庞杂,理解起来不容易。但我们可以从他的继承关系来理解他的能力。这里就不扩展了。

父子上下文

在这里插入图片描述
SpringMVC把上下文分为Servlet容器的上下文,和根应用上下文。这点可能有不少人知道。但是,为什么要这样分呢?先看下两个上下文的职责分工。

  • Servlet上下文包含控制器、试图解析器,以及其他web相关的bean
  • Root上下文,则包含中间层服务,数据源等。

可能有同学会问,为什么要多此一举呢?只使用一个上下文不行吗?还更容易理解。但是,有的情况下,我们的web应用可能不止提供http服务。例如:定时任务。定时任务跟Servlet有关系吗?
从设计原则上说,这种划分可能也是基于最少知识原则,降低系统的耦合,也为其可维护性埋下伏笔。简而言之,web上下文只管web相关的bean,应用上下文管其他与web无关的bean。

Root ApplicationContext怎么加载呢?

DispatcherServlet通过自己的上下文来提供web服务。并且该web上下文还有个父亲。我们很容易想到在DispatcherServlet创建/初始化时,创建一个web上下文并扫描相关的webBean。但是Root ApplicationContext增加加载呢?怎么衔接起来呢?
DispatcherServlet不就是一个servlet吗?通过ServletContext传递不就好了。但是什么时候创建呢?于是我们就需要到tomcat里面来了。
tomcat启动的时候,也有自己的上下文:ServletContext。这个时候,可能有同学要晕车。。其实,你回过头再理解一下上下文,或许就好了。这就类似于我们现实生活中,做不同的事情,所需要了解的背景知识不一样。如果你用SpringCloud,还有个Bootstrap ApplicationContex,可以自己理解一下,它又是干啥的。
当ServletContext初始化完成后,就会发布一个ServletContextEvent。这时只要我们实现ServletContextListener,即可收到通知。于是,我们便可借此机会初始化Root ApplicationContext,并放到ServletContext里面。
在这里插入图片描述

DispatcherServlet启动

DispatcherServlet有一个Web上下文,并且由他管理着所有的web相关的bean。这意味着,在DispatcherServlet具备提供服务的能力之前,我们需要先将这个上下文准备好。而之前说的,只是Root Application。
如果是你,你会怎么做呢?很容易想到就是在创建DispatcherServlet的时候对上下文进行初始化。只不过我们的DispatcherServlet本质上是Servlet,因此只需要跟随Servlet的生命周期函数就好。所以选择在javax.servlet.Servlet#init方法进行初始化。
实际的实现在:org.springframework.web.servlet.FrameworkServlet#initServletBean
要找到他的实际创建和刷新上下文,还是有点绕的,调用链路贴一下:
在这里插入图片描述
而org.springframework.web.servlet.DispatcherServlet#initStrategies方法就是从web上下文中获取DispatcherServlet所依赖的相关的webBean.

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

DispatcherServlet内部的九大组件

从上面的初始化代码来看,有如下组件;
MultipartResolver:文件上传处理器
LocaleResolver:多语言解析器
ThemeResolver: 主题解析器,简单来说就是页面的整体样式。可参考文章
HandlerMapping: 处理器映射器,找到对应的处理器就靠他了
HandlerAdapter:处理器适配器
HandlerExceptionResolver:处理器异常解析器
RequestToViewNameTranslator:将请求翻译成视图名字的解释器
ViewResolver:视图解析器
FlashMapManager:FlashMap管理器。用于重定向请求的。FlashMap本身是一个Map,把跳转前的参数保存在FlashMap中。然后再将其作为Request的session属性进行设置。

从我们经常使用的@RequestMapping的方式声明一个Http接口的角度看,以上组件并不是完全必要的。因此这里不会讨论无关的组件。在这里提醒一下,spring的这些工具可能不止一个实现,不同的实现对应不同的使用场景。例如HandlerMapping的BeanNameUrlHandlerMapping,把bean的名字作为请求uri映射给该bean来处理请求。RequestMappingHandlerMapping则是通过@RequestMapping进行uri地址映射的。本次我们讨论的是与@RequestMapping相关的。

RequestMappingHandlerMapping需要什么信息?
  1. 他需要知道哪些对象有@RequestMapping注解,才能找到uri对应的处理方法。这意味着他需要对所有的bean进行遍历。

    因此需要解析@RequestMapping,包括这些信息:可以处理的uri,以及各种限定条件。例如:该注解可以指定处理POST请求

  2. 他需要按照方法参数来进行参数解析,以便调用目标处理方法

    因此他需要参数转换服务。例如:字符串转Date

RequestMappingHandlerMapping初始化

顺着上面的九大组件的初始化方法找:

> org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
 > org.springframework.web.servlet.DispatcherServlet#getDefaultStrategies

如果没有配置HandlerMapping,那么就会找到org.springframework.web.servlet包下的DispatcherServlet.properties,从这里面加载默认的HandlerMapping.
但这里还没完,因为RequestMappingHandlerMapping实现了InitializingBean接口。而实际上到这里,他也只是创建了这个对象,并没有对我们之前说的各种属性进行初始化。
在afterPropertiesSet方法会调用到下面这个方法

    protected void initHandlerMethods() {
     	// 遍历bean工厂中所有beanName
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			    // 处理候选bean:他会检查bean是否为Controller,如果是,还会注册到MappingRegistry,也即Mapping注册中心。所谓Mapping就是uri->handler
				processCandidateBean(beanName);
			}
		}
		handlerMethodsInitialized(getHandlerMethods());
	}

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

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

相关文章

[附源码]Python计算机毕业设计Django海南琼旅旅游网

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

22.12.1打卡 漫步校园 记忆化搜索

题目里很显然只走最短路, 直接用bfs从终点到起点搜一遍将每一步到终点所需要的最短的时间存在一个dis数组中, 然后你就会发现原来的地图变成了这样 上面是地图下面是dis数组, 再看看经典记忆化搜索模板题滑雪的地图 对的, 非常地相似, 接下来的操作和滑雪基本一样, 只不过起点是…

SQL创建新的输出字段

SQL创建新的输出字段1、准备数据2、对单个字段或者多个字段进行数值计算3、数值计算4、字段拼接5、字段使用别名6、 CASE WHEN逻辑转换case when 语法一case when 语法二case when 注意点查询的值可以为任何值(例如可以: select *)可以重命名…

Docker 快速安装Jenkins完美教程 (亲测采坑后详细步骤)(转)

转载至:https://www.cnblogs.com/fuzongle/p/12834080.html Docker 快速安装Jenkins完美教程 (亲测采坑后详细步骤) Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作&#xff0…

组织:阿米巴-事业部-成员公司

昨天有朋友讲到阿米巴-内部交易的成本与效率、讲到乌合之众山头团伙合并财报。昨天也都谈到方向大致正确品质大致不错极低规模成本、方向老钻错牛角尖品质精密高成本。我这篇文章就是:群中单句交流-朋友圈提炼段落-公众号整理成文章,这么来的。阿米巴&am…

从零开始带你实现一套自己的CI/CD(一)Jenkins

目录一、简介二、环境准备2.1 安装Docker和Docker-compose2.2 远程仓库Github/Gitee/GitLab2.3 部署Jenkins三、配置Jenkins3.1 Jenkins配置源码拉取地址3.2 Jenkins配置Maven构建代码3.2.1 准备jdk3.2.2 配置Maven3.2.3 Jenkins配置JDK&Maven并保存3.3 配置Jenkins任务构建…

【日常折腾】重新安装Windows7,做好ghost备份,迁移主目录,日常软件office,chrome,搜狗输入法,电脑管家,一键ghost进行备份。

目录前言1,关于Windows2,电脑起码分两个盘c、d盘3,因为主目录切换了,相关的其他人软件的数据都会迁移过去4,安装office软件3件套,不要全家桶5,安装电脑管家,还是选择腾讯吧6&#xf…

17条卢松松近期言论汇总

我是卢松松,点点上面的头像,欢迎关注我哦! 本文汇集了前段时间卢松松写的段子,有心情感悟、工作感悟、做直播带货、创业的感悟。关注互联网、草根创业者的朋友可以看看! (1) 人最舒服的是什么时候呢?我认为&#xff…

RabbitMQ的工作模式

一.RabbitMQ的一些知识 1.消息属性 RabbitMQ是基于AMQP消息传输协议来实现的消息中间件;类似HTTP有header和body两部分数据,Message是RabbitMQ中的消息体概念。 Message由Properties和Body组成,前者是一些元信息,如消息的优先级…

【LeetCode】1769.移动所有球到每个盒子所需的最小操作数

题目描述 有 n 个盒子。给你一个长度为 n 的二进制字符串 boxes ,其中 boxes[i] 的值为 ‘0’ 表示第 i 个盒子是 空 的,而 boxes[i] 的值为 ‘1’ 表示盒子里有 一个 小球。 在一步操作中,你可以将 一个 小球从某个盒子移动到一个与之相邻的…

整理Ubuntu深度学习服务器初始化操作

前言 这两年总是换服务器,每次配置都挺麻烦的要搜一堆东西,干脆直接整理一下供自己以后参考。 版本说明 Ubuntu 20.04 桌面版 系统配置 配置SSH 安装ssh sudo apt update sudo apt install openssh-server检查ssh状态 sudo systemctl status ssh…

js将图片或者文件转成base64格式的两种方法

场景一,项目assets资源里面的图片本地图片,重点如下 需要了解 canvas的基本操作,canvas.toDataURL 方法 HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI 。可以使用 type 参数其类型,默认为 PNG 格式。图片…

session和cookie的区别

文章目录一概念理解1、无状态的HTTP协议:2、会话(Session)跟踪:二cookie1、会话Cookie和持久Cookie2、Cookie具有不可跨域名性三. Session1、两个问题:2、session的创建:3、禁用cookie:四. 总结…

GIS工具maptalks开发手册(二)01-02之GeoJSON转化为Geometry——渲染点

GIS工具maptalks开发手册(二)01-02之GeoJSON转化为Geometry——渲染点 效果 1、html官方版 <!DOCTYPE html> <html> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1"> <t…

c实现mp4解封装

文章目录前序MP4简介MP4的定义MP4的封装格式Box类型详解Box格式ftyp boxmvhd boxtkhd boxhdlr boxmdat boxstbl boxstsd boxstco boxstsc boxstsz boxstts boxstss boxdemuxer demo的实现(视频数据部分)总结&#xff1a;工具介绍源码参考前序 最近为了更加深入了解音视频demux…

nginx源码分析--基数树

typedef struct {ngx_radix_node_t *root;ngx_pool_t *pool;ngx_radix_node_t *free;char *start;size_t size; } ngx_radix_tree_t;预备知识 1.基数树也是一种二叉查找树,目前官方模块中仅geo模块使用了基数树.2.ngx_radix_tree_t基数树要求…

微服务框架 SpringCloud微服务架构 8 Gateway 网关 8.7 网关的cors 跨域配置

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构8 Gateway 网关8.7 网关的cors 跨域配置8.7.1 跨域问题处理8.7.2 案例8.7.…

深入讲解Netty那些事儿之从内核角度看IO模型(下)

接上文深入讲解Netty那些事儿之从内核角度看IO模型&#xff08;上&#xff09; epoll 通过上边对select,poll核心原理的介绍&#xff0c;我们看到select,poll的性能瓶颈主要体现在下面三个地方&#xff1a; 因为内核不会保存我们要监听的socket集合&#xff0c;所以在每次调用…

最全面的Spring教程(六)——WebSocket

前言 本文为 【SpringMVC教程】WebSocket 相关知识介绍&#xff0c;具体将对WebSocket进行简介&#xff0c;并通过实战案例对WebSocket的使用进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考&#xff1a;【Java全栈学…

SpringBoot接口 - 如何优雅的写Controller并统一异常处理?

内容目录 为什么要优雅的处理异常 实现案例ControllerAdvice异常统一处理Controller接口运行测试 进一步理解ControllerAdvice还可以怎么用&#xff1f;ControllerAdvice是如何起作用的&#xff08;原理&#xff09;&#xff1f; 示例源码 更多内容 SpringBoot接口如何对异…