SPI广泛用于dubbo,spring boot,spring cloud alibaba等

关于SPI,可见SPI-Service Provider Interface

继续上篇文章

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

而ContextLoaderListener这个类的作用就是启动IOC容器,所以它们作用一致。

现在来看spring web怎么写的。

官方项目就是用的SPI来创建实例,我们聚焦于SpringServletContainerInitializer

  1. /**
    *类的描述:spring应用一启动(tomcat启动的时候)就会去扫描当前应用下导入jar包的META-INF/services的javax.servlet.ServletContainerInitializer的内容,
    *就是SpringServletContainerInitializer,此类中通过@HandlesTypes把WebApplicationInitializer的所有实现类作为onStartup方法的入参,
    *该方法对其中不是抽象类或接口的进行实例化
    */
    @HandlesTypes(WebApplicationInitializer.class)
  2. public class SpringServletContainerInitializer implements ServletContainerInitializer {
  3.  
  4. /**
  5. * Delegate the {@code ServletContext} to any {@link WebApplicationInitializer}
  6. * implementations present on the application classpath.
  7. * <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
  8. * Servlet 3.0+ containers will automatically scan the classpath for implementations
  9. * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
  10. * such types to the {@code webAppInitializerClasses} parameter of this method.
  11. * <p>If no {@code WebApplicationInitializer} implementations are found on the classpath,
  12. * this method is effectively a no-op. An INFO-level log message will be issued notifying
  13. * the user that the {@code ServletContainerInitializer} has indeed been invoked but that
  14. * no {@code WebApplicationInitializer} implementations were found.
  15. * <p>Assuming that one or more {@code WebApplicationInitializer} types are detected,
  16. * they will be instantiated (and <em>sorted</em> if the @{@link
  17. * org.springframework.core.annotation.Order @Order} annotation is present or
  18. * the {@link org.springframework.core.Ordered Ordered} interface has been
  19. * implemented). Then the {@link WebApplicationInitializer#onStartup(ServletContext)}
  20. * method will be invoked on each instance, delegating the {@code ServletContext} such
  21. * that each instance may register and configure servlets such as Spring's
  22. * {@code DispatcherServlet}, listeners such as Spring's {@code ContextLoaderListener},
  23. * or any other Servlet API componentry such as filters.
  24. * @param webAppInitializerClasses all implementations of
  25. * {@link WebApplicationInitializer} found on the application classpath
  26. * @param servletContext the servlet context to be initialized
  27. * @see WebApplicationInitializer#onStartup(ServletContext)
  28. * @see AnnotationAwareOrderComparator
  29. */
  30. @Override
  31. public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
  32. throws ServletException {
  33.  
  34. List<WebApplicationInitializer> initializers = new LinkedList<>();
  35.  
  36. if (webAppInitializerClasses != null) {
  37. for (Class<?> waiClass : webAppInitializerClasses) {
  38. // Be defensive: Some servlet containers provide us with invalid classes,
  39. // no matter what @HandlesTypes says...
  40. if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
  41. WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
  42. try {
  43. initializers.add((WebApplicationInitializer)
  44. ReflectionUtils.accessibleConstructor(waiClass).newInstance());
  45. }
  46. catch (Throwable ex) {
  47. throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
  48. }
  49. }
  50. }
  51. }
  52.  
  53. if (initializers.isEmpty()) {
  54. servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
  55. return;
  56. }
  57.  
  58. servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
  59. AnnotationAwareOrderComparator.sort(initializers);
  60. for (WebApplicationInitializer initializer : initializers) {
  61. initializer.onStartup(servletContext);
  62. }
  63. }
  64.  
  65. }

里面只有一个onStartup方法,而容器启动时会调用此方法。

我们着重看下@HandlesTypes 注解,官方解释:

  1. /**
  2. <p>Because this class declares @{@code HandlesTypes(WebApplicationInitializer.class)},
  3. * Servlet 3.0+ containers will automatically scan the classpath for implementations
  4. * of Spring's {@code WebApplicationInitializer} interface and provide the set of all
  5. * such types to the {@code webAppInitializerClasses} parameter of this method.
  6. */

@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. 2019icpc南京网络赛 A The beautiful values of the palace(离线+树状数组)

    题意: (假设所有的点对应的值已经求出)给你一个1e6*1e6的矩阵,有m<=1e5个点有值,其余都为0 q<=1e5个询问,求子矩阵的权值和 思路: 根据二维差分,对于询问左下角(x1, ...

  2. BZOJ 1009 [HNOI2008]GT考试(矩阵快速幂优化DP+KMP)

    题意: 求长度为n的不含长为m的指定子串的字符串的个数 1s, n<=1e9, m<=50 思路: 长见识了.. 设那个指定子串为s f[i][j]表示长度为i的字符串(其中后j个字符与s ...

  3. Github搜索技巧-如何使用github找到自己感兴趣的项目(转载)

    Github现在不仅仅作为一个版本控制工具,更是一个开源的仓库,里面不但有优秀的开源代码,电子书,还有一些五花八门的项目,有些国家的法律也放在上面,作为程序员如何找到自己感兴趣的项目就非常重要了! 欢 ...

  4. NR / 5G - Uplink Carrier Waveform Generation

  5. pytorch -- CNN 文本分类 -- 《 Convolutional Neural Networks for Sentence Classification》

    论文  < Convolutional Neural Networks for Sentence Classification>通过CNN实现了文本分类. 论文地址: 666666 模型图 ...

  6. logstash 配置文件语法

    需要一个配置文件 管理输入.过滤器和输出相关的配置.配置文件内容格式如下: # 输入 input { ... } # 过滤器 filter { ... } # 输出 output { ... } 先来 ...

  7. php页面传递参数值几种方法总结

    2013-06-06 18:02 (分类:) 又搞了一个学期的php,就这样吧. php是一种服务器的脚本语言,他也是现在最为流行的WEB开发语言,下面我们来讲述一下几种上在php开发应用中常用的四种 ...

  8. CCS过渡和动画

    过渡 过渡能让使用过渡的元素在样式发生变化时(例如鼠标划过,单击按钮,点击图片时,颜色,尺寸,位置等样式发生变化),定义变化过程中的动画,让变化不再是瞬间产生. 过渡样式使用transition定义, ...

  9. 聊聊GIS数据的四个分层与GIS服务

    本篇不讨论矢量栅格数据的结构,也不讨论矢量与栅格的区别(即设定读者有这方面的基础). 版权声明:原创.博客园/B站/小专栏/知乎/CSDN @秋意正寒 转载请标注原地址并声明转载: https://w ...

  10. Java工作流系统jflow从表功能介绍一

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流  bpm工作流系统  java工作流主流框架  自定义工作流引擎 表单设计器  流程设计器 从表也叫明细表, ...