Spring MVC 三 :基于注解配置
Servlet3.0
Servlet3.0是基于注解配置的理论基础。
Servlet3.0引入了基于注解配置Servlet的规范,提出了可拔插的ServletContext初始化方式,引入了一个叫ServletContainerInitializer的接口。
An instance of the ServletContainerInitializer is looked up via the jar services API by the container at container / application startup time. The framework providing an implementation of the ServletContainerInitializer MUST bundle in the META-INF/services directory of the jar file a file called javax.servlet.ServletContainerInitializer, as per the jar services API, that points to the implementation class of the ServletContainerInitializer.
Servlet3.0规范约定:WEB容器(比如tomcat)要通过SPI的方式检查应用jar包的META-INF/services目录下的Servlet容器的初始化类(ServletContainerInitializer接口的实现类),通过调用该实现类的onStartup方法完成Servlet容器的初始化。
此外,Servlet3.0还引入了@HandlesTypes注解,用来指定Servlet容器初始化过程中,WEB容器会认为应用中的哪些类(由@HandlesTypes指定)会参与到Servlet容器的初始化过程中来。
SpringMVC正是通过以上方式实现Servlet容器的初始化的!!!
SpringMVC Servlet容器初始化过程
按照上述理论的指引,探究注解方式配置Spring MVC的原理就没那么困难了。
先看下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rcwAxqtb-1693146405131)(/img/bVc9kPt)]
很容易的,我们发现SpringMVC指定的Servlet容器初始化的实现类为org.springframework.web.SpringServletContainerInitializer。
所以我们找到他看看:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
}
确实是ServletContainerInitializer接口的实现类,@HandlesTypes指定的是WebApplicationInitializer,这个WebApplicationInitializer究竟是个啥东东,我们先放放,我们先来研究一下 SpringServletContainerInitializer类的onStartup方法。
@Overridepublic void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)throws ServletException {List<WebApplicationInitializer> initializers = new LinkedList<>();if (webAppInitializerClasses != null) {for (Class<?> waiClass : webAppInitializerClasses) {// Be defensive: Some servlet containers provide us with invalid classes,// no matter what @HandlesTypes says...if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&WebApplicationInitializer.class.isAssignableFrom(waiClass)) {try {initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());}catch (Throwable ex) {throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);}}}}if (initializers.isEmpty()) {servletContext.log("No Spring WebApplicationInitializer types detected on classpath");return;}servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");AnnotationAwareOrderComparator.sort(initializers);for (WebApplicationInitializer initializer : initializers) {initializer.onStartup(servletContext);}}}
代码逻辑也不算复杂,检查传入的参数webAppInitializerClasses,如果是实现类的话(不是接口或抽象类)则通过反射机制实例化webAppInitializerClasses并强转为WebApplicationInitializer,然后调用WebApplicationInitializer的onStartup方法。
这里有一个小问题:参数webAppInitializerClasses实例化之后,为什么能强转为WebApplicationInitializer?
其实这也是Servlet3.0规范约定的,WEB容器会根据@HandlesTypes的设置,从当前类加载器中查找符合条件的类,当前@HandlesTypes指定的正是WebApplicationInitializer。
之后的操作就都交给WebApplicationInitializer了。
WebApplicationInitializer
WebApplicationInitializer是承担起Servlet3.0规范约定的初始化Servlet容器的那个人:
Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically – as opposed to (or possibly in conjunction with) the traditional web.xml-based approach.
Implementations of this SPI will be detected automatically by SpringServletContainerInitializer, which itself is bootstrapped automatically by any Servlet 3.0 container. See its Javadoc for details on this bootstrapping mechanism.
我们先看一下他的类结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ONu9uceL-1693146405132)(/img/bVc9kPW)]
Spring框架实现了WebApplicationInitializer接口的3个抽象类,最后一个抽象类AbstractAnnotationConfigDispatcherServletInitializer没有onStartup方法,onStartup方法是他的父类实现的。
我们看一下他的父类AbstractDispatcherServletInitializer的onStartup方法:
@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {super.onStartup(servletContext);registerDispatcherServlet(servletContext);}
可以发现他其实是一个模板方法,首先调用了父类的onStartup,之后调用registerDispatcherServlet方法。父类的onStartup方法是实现rootApplicationContext调用的,至于什么是rootApplicationContext我们暂时不管,我们先看一下registerDispatcherServlet方法:
protected void registerDispatcherServlet(ServletContext servletContext) {String servletName = getServletName();Assert.hasLength(servletName, "getServletName() must not return null or empty");WebApplicationContext servletAppContext = createServletApplicationContext();Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());...省略代码
首先调用createServletApplicationContext创建ServletApplicationContext(Servlet容器),之后创建DispathcerServlet并且把创建好的Servlet容器传递给DispatcherServlet(DispatcherServlet要记录他所在的ServletApplicationContext)。
关键代码出现了,Servlet容器的创建过程应该就在这个createServletApplicationContext方法中,是在AbstractAnnotationConfigDispatcherServletInitializer中实现的:
@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();Class<?>[] configClasses = getServletConfigClasses();if (!ObjectUtils.isEmpty(configClasses)) {context.register(configClasses);}return context;}
创建了一个新的AnnotationConfigWebApplicationContext对象,然后调用getServletConfigClasses()方法获取配置类,之后把配置类注册到了新创建的AnnotationConfigWebApplicationContext对象中。这个getServletConfigClasses()方法是没有实现的(应该是我们的实现类需要实现的)。
至此,Spring通过Servlet3.0规范进行初始化的过程应该已经很清晰了:
1.Spring Framework通过WebApplicationInitializer接口的onStartup方法完成Servlet上下文的初始化。
2.Spring Framework已经完成了WebApplicationInitializer接口的大部分实现(提供了3个抽象类),已经通过模板方法完成了大部分的初始化操作。
3. 猜测:应用层只需要扩展AbstractAnnotationConfigDispatcherServletInitializer类实现getServletConfigClasses()方法、返回Servlet的配置类,即可完成初始化。
接下来我们就验证一下上述猜测。
创建基于注解的Spring MVC应用
按照上述猜测,我们只需要扩展AbstractAnnotationConfigDispatcherServletInitializer、实现getServletConfigClasses()方法即可。
我们还是用上篇文章中用过的例子来验证,在动手之前,由于注解方式和web.xml配置方式是冲突的(配置方式会覆盖掉注解方式),所以我们需要删掉web.xml文件(copy出去即可)。
创建一个configuration包,并创建配置类(只要配置Controller的扫描路径即可):
package org.example.configuration;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan("org.example.controller")
public class MvcConfiguration {
}
然后再创建initializer的实现类:
package org.example.configuration;import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[0];}@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[] {MvcConfiguration.class};}@Overrideprotected String[] getServletMappings() {return new String[] {"/"};}
}
其中RootConfigClasse()方法是为RootApplicationContext服务的,我们前面说过了,展示不管这个RootApplicationContext是什么,现在依然也不管他。
getServletConfigClasses方法,返回我们创建的初始化类。
还有一个getServletMappings方法,上面没有提到过,其实是起到web.xml中的servlet-mapping配置的作用的,所以我们直接返回"/" - 默认匹配规则。
启动项目,访问:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PbumTEUE-1693146405132)(/img/bVc9kTd)]
大功告成!
上一篇 Spring MVC 二 :基于xml配置
相关文章:
Spring MVC 三 :基于注解配置
Servlet3.0 Servlet3.0是基于注解配置的理论基础。 Servlet3.0引入了基于注解配置Servlet的规范,提出了可拔插的ServletContext初始化方式,引入了一个叫ServletContainerInitializer的接口。 An instance of the ServletContainerInitializer is looke…...
机器学习基础16-建立预测模型项目模板
机器学习是一项经验技能,经验越多越好。在项目建立的过程中,实 践是掌握机器学习的最佳手段。在实践过程中,通过实际操作加深对分类和回归问题的每一个步骤的理解,达到学习机器学习的目的 预测模型项目模板 不能只通过阅读来掌握…...
ReID网络:MGN网络(4) - Loss计算
1. MGN Loss MGN采用三元损失(Triplet Loss)。 三元损失主要用于ReID算法,目的是帮助网络学习到一个好的Embedding信息。之所以称之为三元损失,主要原因在于在训练中,参与计算Loss的分别有Anchor、Positive和Negative三方。 2. Triplet Lo…...
CountDownLatch、Semaphore详解——深入探究CountDownLatch、Semaphore源码
这篇文章将会详细介绍基于AQS实现的两个并发类CountDownLatch和Semaphore,通过深入底层源代码讲解其具体实现。 目录 CountDownLatch countDown() await() Semaphore Semaphore类图 Semaphore的应用场景 acquire() tryAcquire() CountDownLatch /*** A synchroni…...
windows生成ios证书的方法
使用hbuilderx的uniapp框架开发ios应用,在测试阶段和发布阶段,需要ios证书进行打包,云打包的界面提供了生成ios证书的教程,但是教程令人很失望,它只能使用mac电脑来生成ios证书。假如没有mac电脑,就无法安照…...
【小沐学Unity3d】3ds Max 骨骼动画制作(Physique 修改器)
文章目录 1、简介2、Physique 工作流程3、Physique 对象类型4、Physique 增加骨骼5、Physique 应用和初始化6、Physique 顶点子对象7、Physique 封套子对象8、设置关键点和自动关键点模式的区别8.1 自动关键点8.2 设置关键点 结语 1、简介 官方网址: https://help.…...
生态项目|Typus如何用Sui特性制作动态NFT为DeFi赋能
对于许多人来说,可能因其涉及的期权、认购和价差在内的DeFi而显得晦涩难懂,但Typus Finance找到了一种通过动态NFT使体验更加丰富的方式。Typus NFT系列的Tails为用户带来一个外观逐渐演变并在平台上提升活动水平时获得新特权的角色。 Typus表示&#x…...
IOS打包上架AppStore被驳回信息记录
1:错误码5.2.1错误信息如下 Your app includes content or features from 公司名, or is marketed to control external hardware from 公司名, without the necessary authorization. The inclusion of third-party content within your app, whether retrieved fr…...
【Python自学笔记】Python好用的模块收集(持续更新...)
文章目录 日志模块钉钉机器人命令助手持续更新中,如果您有其他实用好用的模块欢迎留言...日志模块 写代码离不开日志,自定义一个理想的日志对于小白来说可能是一件很反锁的事情,就像我刚学习Python的时候自己写的一个自定义日志,为了解决这个痛点,今天就和大家分享一个可以…...
在springboot中配置mybatis(mybatis-plus)mapper.xml扫描路径的问题
我曾经遇到过类似问题: mybatis-plus的mapper.xml在src/main/java路径下如何配置pom.xml和application.yml_idea 把mapper文件放到java下如何配置_梓沂的博客-CSDN博客 当时只是找到解决问题的办法,但对mybatis配置来龙去脉并未深入了解,所…...
c++搜索剪枝常见方法与技巧
目录 搜索剪枝常见方法与技巧 关键字 搜索方法,剪枝 摘要 正文 小结 程序 参考书目 搜索剪枝常见方法与技巧 关键字 搜索方法,剪枝 摘要 搜索是计算机解题中常用的方法,它实质上是枚举法的应用。由于它相当于枚举法,所以其效率是相当地的。因此…...
YOLO V5 和 YOLO V8 对比学习
参考文章: 1、YOLOv5 深度剖析 2、如何看待YOLOv8,YOLOv5作者开源新作,它来了!? 3、anchor的简单理解 完整网络结构 YOLO v5和YOLO v8的Head部分 YOLO v8的Head 部分相比 YOLOv5 改动较大,换成了目前主流的解耦头结构…...
【Git】(六)子模块跟随主仓库切换分支
场景 主仓库:TestGit 子模块:SubModule 分支v1.0 .gitmodules文件 [submodule "Library/SubModule"]path Library/SubModuleurl gitgitee.com:sunriver2000/SubModule.gitbranch 1.0.0.0 分支v2.0 .gitmodules文件 [submodule "Li…...
开源的经济影响:商业与社区的平衡
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
数据库复习整理
1.group by与where 一,group by 字句也和where条件语句结合在一起使用。当结合在一起时,where在前,group by 在后。 即先对select xx from xx的记录集合用where进行筛选,然后再使用group by 对筛选后的结果进行分组 使用having字句…...
开始MySQL之路——MySQL安装和卸载
MySQL的介绍 MySQL数据库管理系统由瑞典的DataKonsultAB公司研发,该公司被Sun公司收购,现在Sun公司又被Oracle公司收购,因此MySQL目前属于Oracle旗下产品。 MySQL所使用的SQL语言是用于访问数据库的最常用标准化语言。MySQL软件采用了双授权…...
pxe网络装机
PXE是什么? 批量装机系统,网络安装linux操作系统。需要客户端的网卡支持pxe网络启动。 PXE的组件: vsftpd/httpd/nfs 负责提供系统的安装文件 tftp 负责提供系统安装前的引导文件与内核文件 dhcp 负责提供客户端的IP地址分配与pxe引…...
【数据库事务】
数据库事务 何为事务事务的特性原子性 Atomicity一致性 Consistency隔离性 IsolationRead UncommittedRead CommittedRepeatable ReadSerializable 持久性 Durability功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的…...
Apache Tomcat
在Java中,如果您想使用 Apache Tomcat 作为服务器容器,您需要从 Apache Tomcat 官方网站(https://tomcat.apache.org)下载并导入 Tomcat 的相关 JAR 文件。 以下是使用 Tomcat 类创建和配置 Tomcat 服务器的示例代码:…...
python类
python是一种面向对象的变成语言。 python几乎所有的东西都是对象,包括对象和属性。 一.类的定义 python类的定义: class ClassName:pass: 实例: 注意: 类中的函数称为方法,有关于函数的一切适用于方法&…...
【微信小程序 + 登录流程】微信小程序授权登录完整流程,一篇搞定!(含代码实现)
前言 只要开始写一个微信小程序,必要的登录流程每次都要再理一下逻辑,记录一下思路,以便于后面自己食用。 大家有什么更好的思路可以分享~后面想创建一个学习小组,有兴趣的小伙伴可以联系我。 文章目录 前言 一、小程序微信授权登录 1.登录态检查(节点 B) 2.获取临时凭…...
【MySQL】事务:ACID 特性
原子性(atomicity):原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。即要么转账成功,要么转账失败,是不存在中间的状态。如果无法保证原子性会怎么样?就会出现数据不一…...
Qwen3-0.6B-FP8惊艳表现:在‘写一段鲁迅风格评论AI伦理’任务中获人工评分4.8/5
Qwen3-0.6B-FP8惊艳表现:在‘写一段鲁迅风格评论AI伦理’任务中获人工评分4.8/5 最近,一个只有6亿参数的小模型Qwen3-0.6B-FP8,在一项特殊的文本生成任务中,获得了接近满分的评价。这项任务要求模型模仿鲁迅先生的文风࿰…...
全任务零样本学习-mT5中文-base入门必看:温度系数对中文成语/俗语保留率影响
全任务零样本学习-mT5中文-base入门必看:温度系数对中文成语/俗语保留率影响 1. 模型介绍与核心价值 全任务零样本学习-mT5中文-base是一个专门针对中文文本增强优化的AI模型。它在原有mt5模型基础上,使用了海量中文数据进行深度训练,并引入…...
leetcode 困难题 1392. Longest Happy Prefix 最长快乐前缀
Problem: 1392. Longest Happy Prefix 最长快乐前缀 滚动哈希的,取基26,模1e9 11,首先求出字符串的前缀哈希,前缀哈希用到了滚动哈希计算方式 后缀哈希,可以直接套公式求 像cbcb,前缀哈希这么算…...
构建城市可信数据空间:从标准到实践的全方位指南
1. 城市数据困局:我们为什么需要一个“可信”的空间? 想象一下,你所在的城市,交通部门掌握着实时车流数据,环保部门监测着空气质量,卫健委管理着医疗资源分布,而商业平台则记录着市民的消费习惯…...
高清互联双雄@ACP#GSV6155 与 SD642 赋能多场景显示切换新生态
在 Type-C 拓展坞、多屏显示终端、KVM 切换器等设备爆发式增长的当下,信号传输的稳定性、兼容性与切换灵活性成为产品竞争力的核心。基石酷联(GSCoolink)推出的 GSV6155 高性能信号重定时器与 SD642 高速多路复用器,以互补协同的产…...
Phi-3-vision-128k-instruct惊艳案例:化学分子结构图→IUPAC命名→反应活性位点预测
Phi-3-vision-128k-instruct惊艳案例:化学分子结构图→IUPAC命名→反应活性位点预测 1. 模型能力概览 Phi-3-Vision-128K-Instruct是当前最先进的轻量级开放多模态模型,专为处理密集推理任务而设计。这个模型最令人印象深刻的特点是其128K的超长上下文…...
FLUX小红书极致真实V2在VMware虚拟机环境中的部署指南
FLUX小红书极致真实V2在VMware虚拟机环境中的部署指南 想在虚拟化环境中体验高质量AI图像生成?这篇教程将手把手教你如何在VMware虚拟机中部署FLUX小红书极致真实V2模型。 1. 环境准备与虚拟机配置 在开始部署之前,我们需要先准备好合适的虚拟机环境。F…...
QJ71GP21S-SX三菱网络模块
QJ71GP21S-SX 是三菱电机 MELSEC-Q 系列的 CC-Link IE 控制器网络模块(光纤型、双回路、带外部供电),专为中大型分布式控制系统提供 1Gbps 超高速、大容量、高可靠的 PLC 间互联与数据共享能力。一、产品特性1Gbps 超高速光纤通信:…...
