AbstractDispatcherServletInitializer 的实现类为什么可以在初始化Web容器的时候被调用

本文介绍了SpringMVC中如何使用SPI服务发现机制注册DispatcherServlet。Spring通过在spring-web.jar的META-INF/services目录下注册ServletContainerInitializer,使得Servlet容器在启动时能通过SPI加载SpringServletContainerInitializer,进而调用WebApplicationInitializer的onStartup方法,包括AbstractDispatcherServletInitializer的onStartup,完成SpringMVC的初始化配置。

引入

在学习 Spring MVC 引入 Java Web项目的时候,发现除了使用 web.xml 注册 DispatcherServlet 的方式,还可以使用配置类继承 AbstractDispatcherServletInitializer 的方式进行 DispatcherServlet 这个前端控制器的注册。于是好奇我们写的 DispatcherServletInitializer 配置类怎么能被 Web 容器识别并加载。

解析

DispatcherServletInitializer 配置类能够被加载的核心是 Java 的 SPI 服务发现机制。

SPI 服务发现机制

  1. 服务接口 的定义: 某一个框架定义了某种服务的 接口 ,我们在使用这个框架的时候可以使用不同的服务提供商提供的接口的实现。
  2. 注册 服务接口 的实现: 在 classpath:META-INF/services/目录下创建一个以 服务接口 全类名命名的文件,内容为实现类的全类名。
  3. 服务加载 定义了 服务接口 的框架在启动时会到 SPI 规范指定的 classpath:META-INF/services/目录下寻找并加载此框架所需服务。

Spring MVC 遵循 SPI 规范,作为Servlet容器的服务提供商向其注册服务

对应于SPI 服务发现机制的三点

  1. 服务接口 的定义 Servlet 规范定义了服务接口 javax-servlet-api-xxx.jar/javax.servlet.ServletContainerInitializer
  2. 注册 服务接口 的实现: Spring MVC 注册服务。在 spring-web-xxx.jar 包下 有 META-INF/services/javax.servlet.ServletContainerInitializer 文件,内容为 org.springframework.web.SpringServletContainerInitializer
  3. 服务加载 SpringServletContainerInitializer 中的 onStartup 方法会在 Servlet 容器初始化的时候通过 SPI 机制发现并调用,onStartup 方法里面又会 将所有 WebApplicationInitializer 的实现类的对象的 onStartup 方法全部调用一遍。文章开头所说的 AbstractDispatcherServletInitializer 也是 WebApplicationInitializer 接口的实现,所以其 onStartup 方法也会在 Servlet 容器初始化的时候被调用。

展望

关于 SpringServletContainerInitializer 如何加载 WebApplicationInitializer 还有待研究。

参考

Java编程技术之浅析SPI服务发现机制

附录

继承 AbstractDispatcherServletInitializer 方式引入 Spring MVC

public class DispatcherServletInitializer extends AbstractDispatcherServletInitializer {
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
        applicationContext.register(SpringMvcConfig.class);
        return applicationContext;
    }

    @Override
    protected String[] getServletMappings() {
        // "/" 所有,但不包括.jsp/.html; "/*" 表示包括.jsp/.html 的所有
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值