spring mvc源码学习笔记之十

前面的文章介绍了用 WebApplicationInitializer 或者 AbstractAnnotationConfigDispatcherServletInitializer 来代替 web.xml
我们学 java web 的时候就知道,servlet 容器会自动加载 web.xml
那么,疑问就来了,WebApplicationInitializer 或者 AbstractAnnotationConfigDispatcherServletInitializer 既然替代了 web.xml,那应该也会被 servlet 容器加载,是不是这样呢?答案是:是的。
而完成这个加载工作的是 SpringServletContainerInitializer 类。看下它的源码:

package org.springframework.web;  import java.lang.reflect.Modifier;  
import java.util.LinkedList;  
import java.util.List;  
import java.util.ServiceLoader;  
import java.util.Set;  
import javax.servlet.ServletContainerInitializer;  
import javax.servlet.ServletContext;  
import javax.servlet.ServletException;  
import javax.servlet.annotation.HandlesTypes;  import org.springframework.core.annotation.AnnotationAwareOrderComparator;  
import org.springframework.lang.Nullable;  
import org.springframework.util.ReflectionUtils;  /**
* 本类继承了 servlet 3.0 的 ServletContainerInitializer 接口。
* 下面这段话的意思是:
* servlet 3.0 的 ServletContainerInitializer 接口是用来让 servlet 容器支持基于编码的配置。
* 在这个过程中要结合 spring 的 WebApplicationInitializer。
* 而 spring 的 WebApplicationInitializer 可以替换 web.xml 也可以结合 web.xml 一起使用。
*
* Servlet 3.0 {@link ServletContainerInitializer} designed to support code-based  
* configuration of the servlet container using Spring's {@link WebApplicationInitializer}  
* SPI as opposed to (or possibly in combination with) the traditional  
* {@code web.xml}-based approach.  
*
* 当 servlet 容器启动的时候,如果累路径下有 spring-web 的话,这个类会被加载,并且 onStartup 方法会被调用。
* 这背后的原理在于 java 的 SPI 机制。
* spring-web 模块下有个 META-INF/services/javax.servlet.ServletContainerInitializer 文件,
* 其内容就是当前类的完全限定名。
*
* <h2>Mechanism of Operation</h2>  
* This class will be loaded and instantiated and have its {@link #onStartup}  
* method invoked by any Servlet 3.0-compliant container during container startup assuming  
* that the {@code spring-web} module JAR is present on the classpath. This occurs through  
* the JAR Services API {@link ServiceLoader#load(Class)} method detecting the  
* {@code spring-web} module's {@code META-INF/services/javax.servlet.ServletContainerInitializer}  
* service provider configuration file. See the  
* <a href="http://download.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#Service%20Provider">  
* JAR Services API documentation</a> as well as section <em>8.2.4</em> of the Servlet 3.0  
* Final Draft specification for complete details.  
*  
* <h3>In combination with {@code web.xml}</h3>  
* A web application can choose to limit the amount of classpath scanning the Servlet  
* container does at startup either through the {@code metadata-complete} attribute in  
* {@code web.xml}, which controls scanning for Servlet annotations or through an  
* {@code <absolute-ordering>} element also in {@code web.xml}, which controls which  
* web fragments (i.e. jars) are allowed to perform a {@code ServletContainerInitializer}  
* scan. When using this feature, the {@link SpringServletContainerInitializer}  
* can be enabled by adding "spring_web" to the list of named web fragments in  
* {@code web.xml} as follows:  
*  
* <pre class="code">  
* {@code  
* <absolute-ordering>  
* <name>some_web_fragment</name>  
* <name>spring_web</name>  
* </absolute-ordering>  
* }</pre>  
*
* SpringServletContainerInitializer 可以看做一个简单的代理,真正的工作还是交给了 WebApplicationInitializer 。
*
* <h2>Relationship to Spring's {@code WebApplicationInitializer}</h2>  
* Spring's {@code WebApplicationInitializer} SPI consists of just one method:  
* {@link WebApplicationInitializer#onStartup(ServletContext)}. The signature is intentionally  
* quite similar to {@link ServletContainerInitializer#onStartup(Set, ServletContext)}:  
* simply put, {@code SpringServletContainerInitializer} is responsible for instantiating  
* and delegating the {@code ServletContext} to any user-defined  
* {@code WebApplicationInitializer} implementations. It is then the responsibility of  
* each {@code WebApplicationInitializer} to do the actual work of initializing the  
* {@code ServletContext}. The exact process of delegation is described in detail in the  
* {@link #onStartup onStartup} documentation below.  
*  
* <h2>General Notes</h2>  
* In general, this class should be viewed as <em>supporting infrastructure</em> for  
* the more important and user-facing {@code WebApplicationInitializer} SPI. Taking  
* advantage of this container initializer is also completely <em>optional</em>: while  
* it is true that this initializer will be loaded and invoked under all Servlet 3.0+  
* runtimes, it remains the user's choice whether to make any  
* {@code WebApplicationInitializer} implementations available on the classpath. If no  
* {@code WebApplicationInitializer} types are detected, this container initializer will  
* have no effect.  
*  
* <p>Note that use of this container initializer and of {@code WebApplicationInitializer}  
* is not in any way "tied" to Spring MVC other than the fact that the types are shipped  
* in the {@code spring-web} module JAR. Rather, they can be considered general-purpose  
* in their ability to facilitate convenient code-based configuration of the  
* {@code ServletContext}. In other words, any servlet, listener, or filter may be  
* registered within a {@code WebApplicationInitializer}, not just Spring MVC-specific  
* components.  
*
* 注意:不要扩展这个类,也不要继承这个类。
* 这个类应该被视为内部类型,不对外。
* 对外的是 WebApplicationInitializer。
*
* <p>This class is neither designed for extension nor intended to be extended.  
* It should be considered an internal type, with {@code WebApplicationInitializer}  
* being the public-facing SPI.  
*  
* <h2>See Also</h2>  
* See {@link WebApplicationInitializer} Javadoc for examples and detailed usage  
* recommendations.<p>  
*  
* @author Chris Beams  
* @author Juergen Hoeller  
* @author Rossen Stoyanchev  
* @since 3.1  
* @see #onStartup(Set, ServletContext)  
* @see WebApplicationInitializer  
*/  
@HandlesTypes(WebApplicationInitializer.class)  
public class SpringServletContainerInitializer implements ServletContainerInitializer {  {  System.out.println("@HandlesTypes(WebApplicationInitializer.class) 这个注解表明了当前类 SpringServletContainerInitializer "+ " 需要处理的类型是 WebApplicationInitializer ");  
}  /**  
* Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}  
* implementations present on the application classpath.
* 
* <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},  
* Servlet 3.0+ containers will automatically scan the classpath for implementations  
* of Spring's {@code WebApplicationInitializer} interface and provide the set of all  
* such types to the {@code webAppInitializerClasses} parameter of this method.  
* <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,  
* this method is effectively a no-op. An INFO-level log message will be issued notifying  
* the user that the {@code ServletContainerInitializer} has indeed been invoked but that  
* no {@code WebApplicationInitializer} implementations were found.  
* <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,  
* they will be instantiated (and <em>sorted</em> if the @{@link  
* org.springframework.core.annotation.Order @Order} annotation is present or  
* the {@link org.springframework.core.Ordered Ordered} interface has been  
* implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}  
* method will be invoked on each instance, delegating the {@code ServletContext} such  
* that each instance may register and configure servlets such as Spring's  
* {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},  
* or any other Servlet API componentry such as filters.  
* @param webAppInitializerClasses all implementations of  
* {@link WebApplicationInitializer} found on the application classpath  
* @param servletContext the servlet context to be initialized  
* @see WebApplicationInitializer#onStartup(ServletContext)  
* @see AnnotationAwareOrderComparator  
*/  
@Override  
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)  
throws ServletException {  servletContext.log("SpringServletContainerInitializer 利用了 java 的 SPI 机制");  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);  
}  
}  
}  
}  System.out.println("SpringServletContainerInitializer 在其 onStartup 方法中检测类路径下的 WebApplicationInitializer(spring的) ");  if (initializers.isEmpty()) {  
servletContext.log("在类路径下没有检测到 spring 的 WebApplicationInitializer。------- No Spring WebApplicationInitializer types detected on classpath");  
return;  
}  System.out.println("在类路径下检测到了 " + initializers.size() + " 个 spring 的 WebApplicationInitializer。");  servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");  AnnotationAwareOrderComparator.sort(initializers);  System.out.println("依次调用 WebApplicationInitializer 的 onStartup 方法");  for (WebApplicationInitializer initializer : initializers) {  System.out.println("调用 " + initializer.getClass().getName() + " 的 onStartup 方法");  initializer.onStartup(servletContext);  
}  System.out.println("至此,通过 servlet、java spi 成功引导了 spring ");  }  }

关于这个类有几个需要注意的点:

  • 它实现了 servlet 3.0 的 javax.servlet.ServletContainerInitializer 接口
  • 它加了个 @HandlesTypes(WebApplicationInitializer.class) 注解
  • 它实现了 javax.servlet.ServletContainerInitializer 接口中定义的 onStartup 方法

总结下来。SpringServletContainerInitializer 这个类实现了 servlet 3.0 的 javax.servlet.ServletContainerInitializer 接口,这就决定了在 servlet 容器启动的时候 onStartUp 方法会被自动触发,而在 onStartUp 方法内部 WebApplicationInitializeronStartUp 方法被调用。这就是 WebApplicationInitializer 被容器带起来的过程。

这里只是说了个大概,要想非常清楚,还请自己研究下 servlet 3.0 的 javax.servlet.ServletContainerInitializer 接口。

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

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

相关文章

基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化

基于 Apache Commons Pool 实现的 gRPC 连接池管理类 GrpcChannelPool 性能分析与优化 1. 输出关键信息的代码示例 日志记录方法 使用以下代码记录连接池的关键信息&#xff0c;帮助分析连接池的状态和性能瓶颈&#xff1a; import org.apache.commons.pool2.impl.GenericO…

小程序开发-页面事件之上拉触底实战案例

&#x1f3a5; 作者简介&#xff1a; CSDN\阿里云\腾讯云\华为云开发社区优质创作者&#xff0c;专注分享大数据、Python、数据库、人工智能等领域的优质内容 &#x1f338;个人主页&#xff1a; 长风清留杨的博客 &#x1f343;形式准则&#xff1a; 无论成就大小&#xff0c;…

STM32-笔记38-I2C-oled实验

一、什么是I2C&#xff1f; I2C总线&#xff0c;全称Inter-Integrated Circuit&#xff08;互连集成电路&#xff09;&#xff0c;是一种由Philips&#xff08;现NXP半导体&#xff09;公司在1980年代初开发的同步 串行 半双工通信总线。 二、有了串口通信为什么要使用I2C&…

《C++11》右值引用深度解析:性能优化的秘密武器

C11引入了一个新的概念——右值引用&#xff0c;这是一个相当深奥且重要的概念。为了理解右值引用&#xff0c;我们需要先理解左值和右值的概念&#xff0c;然后再理解左值引用和右值引用。本文将详细解析这些概念&#xff0c;并通过实例进行说明&#xff0c;以揭示右值引用如何…

libevent定时器的性能测试(与rte_timer对比)

前言 接着上篇文章&#xff0c;rte_timer的性能测试https://blog.csdn.net/jacicson1987/article/details/144997298 进行常用的libevent的定时器测试&#xff0c;看看有什么区别&#xff0c;测试方法还是一样&#xff0c;代码放在下面。 测试方法 100万个定时器&#xff0…

C# 事件

目录 1、事件模型的5个组成部分2、使用内置委托类型声明事件2.1 EventHandler2.1.1 &#xff1f;2.1.2 this2.1.3 使用匿名函数和lamda表达式2.1.3.1 匿名函数2.1.3.2 lamda表达式 2.1.4 异常处理 2.2 EventHandler<TEventArgs> 3、使用自定义委托类型声明事件3.1 事件的…

英伟达 RTX 5090 显卡赋能医疗大模型:变革、挑战与展望

一、英伟达 RTX 5090 与 RTX 4090 技术参数对比 1.1 核心架构与制程工艺 在探讨英伟达 RTX 4090 与 RTX 5090 的差异时&#xff0c;核心架构与制程工艺无疑是最为关键的基础要素&#xff0c;它们从根本上决定了两款显卡的性能上限与应用潜力。 1.1.1 核心架构差异 RTX 4090…

爬虫学习记录

1.概念 通过编写程序,模拟浏览器上网,然后让其去互联网上抓取数据的过程 通用爬虫:抓取的是一整张页面数据聚焦爬虫:抓取的是页面中的特定局部内容增量式爬虫:监测网站中数据更新的情况,只会抓取网站中最新更新出来的数据 robots.txt协议: 君子协议,网站后面添加robotx.txt…

玩机搞机基本常识-------列举安卓机型一些不常用的adb联机命令

前面分享过很多 常用的adb命令&#xff0c;今天分享一些不经常使用的adb指令。以作备用 1---查看当前手机所有app包名 adb shell pm list package 2--查看当前机型所有apk包安装位置 adb shell pm list package -f 3--- 清除指定应用程序数据【例如清除浏览器应用的数据】 …

【25考研】川大计算机复试情况,重点是啥?怎么准备?

24年进入复试的同学中&#xff0c;有10位同学的复试成绩为0分。具体是个人原因还是校方原因&#xff0c;还尚不明确。但是C哥提醒&#xff0c;一定要认真复习&#xff01;复试完后不要跟任何人讨论有关复试的题目及细节&#xff01; 一、复试内容 四川大学复试内容较多&#xf…

计算机的错误计算(二百零五)

摘要 基于一位读者的问题&#xff0c;提出题目&#xff1a;能用数值计算证明 吗&#xff1f;请选用不同的点&#xff08;即差别大的数&#xff09;与不同的精度。实验表明&#xff0c;大模型理解了题意。但是&#xff0c;其推理能力值得商榷。 例1. 就摘要中问题&#xff0…

回归预测 | MATLAB实GRU多输入单输出回归预测

回归预测 | MATLAB实GRU多输入单输出回归预测 目录 回归预测 | MATLAB实GRU多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 回归预测 | MATLAB实GRU多输入单输出回归预测。使用GRU作为RNN的一种变体来处理时间序列数据。GRU相比传统的RNN有较好的记…

unity学习12:地图相关的一些基础2, 增加layer种草种树

目录 参考学习 1 地图设置 1.1 上次制作的地图&#xff0c;稍微加点地形完善下. 1.2 调整下camera 1.3 摄像机camera的移动速度 1.4 地图属性&#xff0c;terrain settings 1.5 但是&#xff0c;地图看起来像沙漠一样&#xff0c;很单调 2 paint terrain / paint textu…

数据挖掘——数据预处理

数据挖掘——数据预处理 数据预处理数据预处理 ——主要任务数据清洗如何处理丢失的数据如何处理噪声数据如何处理不一致数据 数据集成相关分析相关系数(也成为皮尔逊相关系数)协方差 数据规约降维法&#xff1a;PCA主成分分析降数据——抽样法数据压缩 数据预处理 数据预处理…

Python入门教程 —— 网络编程

1.网络通信概念 简单来说,网络是用物理链路将各个孤立的工作站或主机相连在一起,组成数据链路,从而达到资源共享和通信的目的。 使用网络的目的,就是为了联通多方然后进行通信,即把数据从一方传递给另外一方。 前面的学习编写的程序都是单机的,即不能和其他电脑上的程…

鸿蒙APP之从开发到发布的一点心得

引言&#xff1a; 做鸿蒙开发大概有1年左右时间了&#xff0c;从最开始的看官方文档、看B站视频&#xff0c;到后来成功发布两款个人APP&#xff08;房贷计算极简版、时简时钟 轻喷&#xff0c;谢谢&#xff09;。简单描述一下里边遇到的坑以及一些经历吧。 学习鸿蒙开发 个…

力扣刷题:数组OJ篇(上)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 目录 1.消失的数字&#xff08;1&#xff09;题目描…

linux下多个硬盘划分到同一挂载点

Linux下多个硬盘划分到同一挂载点 需要明确的几个概念 物理卷: 物理卷是物理存储设备&#xff08;如硬盘分区、整个硬盘、RAID 阵列等&#xff09;在逻辑卷管理&#xff08;LVM - Logical Volume Manager&#xff09;系统中的抽象表示。它是构建逻辑卷组的基本单元 假设我们有…

2.STM32F407ZGT6-外部中断

参考&#xff1a; 1.正点原子。 前言&#xff1a; MCU最重要的一个领域–中断。总结下嵌套向量和外部中断的概念。达到&#xff1a; 1.NVIC是什么&#xff0c;了解中断的整体管理理念。 2.中断里面最简单的外部中断&#xff0c;怎么配置处理。 3.使用STM32CubeMX配置外部中断的…

《HeadFirst设计模式》笔记(下)

代理模式 代理要做的就是控制和管理访问。 你的客户对象所做的就像是在做远程方法调用&#xff0c;但其实只是调用本地堆中的“代理”对象上的方法&#xff0c;再由代理处理所有网络通信的低层细节。 Java的RMI提供了客户辅助对象和服务辅助对象&#xff0c;为客户辅助对象…