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的更多相关文章

  1. Spring Boot源码(一):去除web.xml

    访问https://spring.io/ spring boot中: public class MyWebApplicationInitializer implements WebApplicatio ...

  2. Spring Boot源码中模块详解

    Spring Boot源码中模块详解 一.源码 spring boot2.1版本源码地址:https://github.com/spring-projects/spring-boot/tree/2.1 ...

  3. 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  4. 精尽Spring Boot源码分析 - 支持外部 Tomcat 容器的实现

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  5. 走进Spring Boot源码学习之路和浅谈入门

    Spring Boot浅聊入门 **本人博客网站 **IT小神 www.itxiaoshen.com Spring Boot官网地址:https://spring.io/projects/spring ...

  6. 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...

  7. Spring Boot源码分析-配置文件加载原理

    在Spring Boot源码分析-启动过程中我们进行了启动源码的分析,大致了解了整个Spring Boot的启动过程,具体细节这里不再赘述,感兴趣的同学可以自行阅读.今天让我们继续阅读源码,了解配置文 ...

  8. Spring Boot源码分析-启动过程

    Spring Boot作为目前最流行的Java开发框架,秉承"约定优于配置"原则,大大简化了Spring MVC繁琐的XML文件配置,基本实现零配置启动项目. 本文基于Spring ...

  9. 曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  10. 曹工说Spring Boot源码(30)-- ConfigurationClassPostProcessor 实在太硬核了,为了了解它,我可能debug了快一天

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

随机推荐

  1. Python中zip()函数的解释和可视化

    zip()的作用 先看一下语法: zip(iter1 [,iter2 [...]]) -> zip object Python的内置help()模块提供了一个简短但又有些令人困惑的解释: 返回一 ...

  2. 《Python学习手册 第五版》 -第8章 列表与字典

    前面已经讲过数值类型(第5章)和字符串类型(第7章),本章继续其他数据类型的讲解:列表和字典 本章的核心内容 1.列表 1)什么是列表 2)基本列表操作 3)列表迭代和推导 4)索引.分片和矩阵 5) ...

  3. Golang设置https访问,以及http如何重定向到https

    设置https访问: 原始代码为http监听: func main() { server := &http.Server{ Addr: ":8080", ... } go ...

  4. Thread Based Parallelism - Thread in a Subclass

    Thread Based Parallelism - Thread in a Subclass 1 import threading import time exit_Flag = 0 class m ...

  5. ajax面试要点

    目录 目录 ajax是什么? 优点 缺点 ajax的工作原理 如何创建一个ajax(ajax的交互模型) ajax过程中get和post的区别 同步和异步的区别 JavaScript 的同源策略 如何 ...

  6. VFP的13个SPT函数

    Visual FoxPro 中内置了13个以SQL开头的函数,我们把它们称为SPT函数.就是这13个函数完成了Visual FoxPro的所有的SQL Pass Though功能.从功能上看,我们可以 ...

  7. linux 统计文件夹下文件,文件夹,所有个数

    统计某文件夹下文件的个数 ls -l |grep "^-"|wc -l 统计某文件夹下目录的个数 ls -l |grep "^d"|wc -l 统计文件夹下文件 ...

  8. python3 kubernetes api 使用

    一.安装 github:https://github.com/kubernetes-client/python 安装 pip install kubernetes 二.认证 1.kubeconfig文 ...

  9. CodeForces 327B 水题。

    I - 9 Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Statu ...

  10. 算法将一个对象中的某一个key值变为true,其他值都为false

    主要运用在,v-if v-show切换不同内容时,非常快的打开某一个区域,关闭其他的区域哈. 这样就不需要每一个设置false,打开区域设置为true. 可以优化代码哈 for in 主要循环对象(空 ...