Spring Boot源码(二):SPI去除web.xml
SPI广泛用于dubbo,spring boot,spring cloud alibaba等
关于SPI,可见SPI-Service Provider Interface
继续上篇文章

上面三句代码的意思是创建IOC容器,下面是向容器中注入DispatcherServlet。

而ContextLoaderListener这个类的作用就是启动IOC容器,所以它们作用一致。
现在来看spring web怎么写的。

官方项目就是用的SPI来创建实例,我们聚焦于SpringServletContainerInitializer
/**
*类的描述:spring应用一启动(tomcat启动的时候)就会去扫描当前应用下导入jar包的META-INF/services的javax.servlet.ServletContainerInitializer的内容,
*就是SpringServletContainerInitializer,此类中通过@HandlesTypes把WebApplicationInitializer的所有实现类作为onStartup方法的入参,
*该方法对其中不是抽象类或接口的进行实例化
*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer { /**
* 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 { 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);
}
} }
里面只有一个onStartup方法,而容器启动时会调用此方法。
我们着重看下@HandlesTypes 注解,官方解释:
/**
<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.
*/
@HandlesTypes 注解会把WebApplicationInitializer的所有子类(可用快捷键Ctrl+Alt+B)放到Set集合中:


然后循环判断此类不为抽象类,不为接口,并且是实现了WebApplicationInitializer接口的,然后实例化对象添加到initializers中:

然后对其进行排序:

这个排序就是通过@Order来判断先后顺序的(或者实现Order接口)。
然后分别循环子类的OnStartup方法。
Spring Boot源码(二):SPI去除web.xml的更多相关文章
- Spring Boot源码(一):去除web.xml
访问https://spring.io/ spring boot中: public class MyWebApplicationInitializer implements WebApplicatio ...
- Spring Boot源码中模块详解
Spring Boot源码中模块详解 一.源码 spring boot2.1版本源码地址:https://github.com/spring-projects/spring-boot/tree/2.1 ...
- 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- 走进Spring Boot源码学习之路和浅谈入门
Spring Boot浅聊入门 **本人博客网站 **IT小神 www.itxiaoshen.com Spring Boot官网地址:https://spring.io/projects/spring ...
- 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解
写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...
- Spring Boot源码分析-配置文件加载原理
在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...
- Spring Boot源码分析-启动过程
Spring Boot作为目前最流行的Java开发框架,秉承"约定优于配置"原则,大大简化了Spring MVC繁琐的XML文件配置,基本实现零配置启动项目. 本文基于Spring ...
- 曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- 曹工说Spring Boot源码(30)-- ConfigurationClassPostProcessor 实在太硬核了,为了了解它,我可能debug了快一天
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
随机推荐
- TensorFlow中使用GPU
TensorFlow默认会占用设备上所有的GPU以及每个GPU的所有显存:如果指定了某块GPU,也会默认一次性占用该GPU的所有显存.可以通过以下方式解决: 1 Python代码中设置环境变量,指定G ...
- 2、HotSpot虚拟机对象探秘
基于使用优先的原则,以常用的虚拟机HotSpot和常用的内存区域Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配.布局和访问的全过程. 1.对象的创建 划分可用空间 在语言层面上,创 ...
- 对c语言中static函数的理解
先看看前两篇博客:个人对头文件的理解.对声明和定义的理解. static 函数只在定义该static函数的cpp中可见,在其他cpp中是不可见的. 举个例子,我建立了一个project,该projec ...
- gridFS-Nginx的安装与使用
在使用gridFs的nginx模块时,先确认好你的机器上已经安装好了mongo 首先通过git将最新的gridfs的nginx模块下载到本地 git clone https://github.com/ ...
- javascript Math对象 常用数字操作方法
var t='1.2'; parseInt(t) parseFloat(t)//1.2 Number(1.2)//1.2强制转换为数字 2.向上取整,有小数就整数部分加1 js: Math.ceil( ...
- 使用GitHub+Travis-CI+Docker打造自动化流水线
全文采用的是阿里云的ESC服务器,系统是CentOS 7 示例项目是NodeJS编写,本文主要是Docker的使用,在文章前2/3都是Docker命令介绍,最后我们会完成一个自动化的示例. 准备 注册 ...
- Nginx是什么 ? 能干嘛 ?
学习博客:https://blog.csdn.net/forezp/article/details/87887507 学习博客:https://blog.csdn.net/qq_29677867/ar ...
- 查看Linux系统内存、CPU、磁盘使用率和详细信息
一.查看内存占用 1.free # free -m 以MB为单位显示内存使用情况 [root@localhost ~]# free -m total used free shared buff/cac ...
- vue.extend 拓展
https://www.w3cplus.com/vue/vue-extend.html https://jspang.com/post/vue2-2.html https://blog.csdn.ne ...
- 解决IIS程序池回收webapi定时程序造成的影响
问题描述: webapi中有一个定时器线程,在iis程序池在1740分钟回收后,定时器中止 问题解决步骤: 1.设置程序池定期回收,设置每天定时回收 2.在windows自带的任务计划中,添加一条任务 ...