深入Spring Boot :web

characterEncodingFilter

/*

springMVC

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath*:springMVC.xml

1

springmvc

/

以上的web.xml在应用启动的时候会创建两个Spring上下文,一个由ContextLoaderListener创建的上下文,一个由DispatcherServlet创建的上下文。ContextLoaderListener创建的上下文用于装载非web功能相关的bean,例如Service、DAO等,而DispatcherServlet创建的上下文用于装载web功能相关的bean,例如Controller、ViewResolver等。ContextLoaderListener创建的上下文要装载的bean来自于web.xml中通过context-param标签配置的contextConfigLocation指定的xml,例如classpath_:spring/_.xml;而DispatcherServlet创建的上下文要装载的bean来自于web.xml中配置的DispatcherServlet中通过init-param标签配置的contextConfigLocation指定的xml,例如classpath*:springMVC.xml,如果没有通过init-param标签配置contextConfigLocation,默认使用以DispatcherServlet在web.xml中配置的servlet-name为前缀,-servlet.xml为后缀的xml文件,例如springMVC-servlet.xml。

Servlet3+弱化web.xml

==================

Servlet3.0在Servlet2.5的基础上提供了若干新特性用于简化Web应用的开发和部署,在servlet-api.jar的javax.servlet.annotation包中新增了@WebServlet、@WebFilter和@WebListener注解,用于简化Servlet、过滤器和监听器的声明,也就是说从此之后开发web应用不一定非要使用web.xml了,例如如下代码声明了一个自定义Filter。

深入Spring Boot (十五):web.xml去哪了

在Servlet3.0 API中提供了一个

javax.servlet.ServletContainerInitializer接口,接口只有一个onStartup方法,在支持Servlet3.0的Web应用服务器中,例如Tomcat7或更高版本,服务器会在启动的时候在类路径下查找javax.servlet.ServletContainerInitializer接口的实现类,执行实现类的onStartup方法用于配置Servlet容器,例如注册Servlet、Filter或Listener。

深入Spring Boot (十五):web.xml去哪了

onStartup方法有两个参数:Set<Class<?>> c和ServletContext ctx,ServletContext即Servlet上下文,它定义了一些方法用于和Servlet容器进行交流,也可以获取web应用的一些资源信息;如果

ServletContainerInitializer接口的实现类使用@HandlesTypes注解声明了感兴趣的类或接口,那么这个感兴趣的类及其子类或接口的实现类就会被设置到Set<Class<?>> c中。

ServletContainerInitializer接口的具体使用方法必须在代码的classpath下的META-INF/services/路径下定义一个名为javax.servlet.ServletContainerInitializer的文件,这个文件的内容是ServletContainerInitializer接口实现类的全路径,例如com.example.demo.MyServletContainerInitializer,下面实现一个简单的MyServletContainerInitializer。

深入Spring Boot (十五):web.xml去哪了

从上图可以看到,ServletContext提供了可以注册Servlet、Filter和Listener的方法,下面动态注册一个Servlet和Filter。

深入Spring Boot (十五):web.xml去哪了

Servlet3.0新增的这些特性在弱化web.xml,下面来看一下Spring是如何支持Servlet3的。

Spring3+逐渐替换web.xml

===================

Spring框架从3.1版本开始支持Servlet3.0,可以在基于Java的配置中声明Servlet、Filter和Listener,并且从3.2版本开始可以使用

AbstractAnnotationConfigDispatcherServletInitializer的子类来配置DispatcherServlet,它会创建DispatcherServlet和ContextLoaderListener,真正实现不再需要使用web.xml,例如如下代码自定义了一个DispatcherServletInitializer,它继承了AbstractAnnotationConfigDispatcherServletInitializer。

深入Spring Boot (十五):web.xml去哪了

深入Spring Boot (十五):web.xml去哪了

DispatcherServletInitializer分别实现了getRootConfigClasses、getServletConfigClasses和getServletMappings方法。getRootConfigClasses方法返回使用@Configuration标注的类用于ContextLoaderListener创建Spring上下文装载非web相关的bean。getServletConfigClasses方法返回使用@Configuration标注的类用于DispatcherServlet创建Spring上下文装载web相关的bean。getServletMappings方法返回的字符串数组用于告诉DispatcherServlet处理那些url的请求。到这里这三个方法的用途是不是很熟悉,其实就是web.xml中配置的DispatcherServlet和ContextLoaderListener替代方案。

Spring3.1中的SpringServletContainerInitializer实现了ServletContainerInitializer接口,同时在相应的jar包META-INF/services/路径下定义了javax.servlet.ServletContainerInitializer文件,它的内容是org.springframework.web.SpringServletContainerInitializer。

深入Spring Boot (十五):web.xml去哪了

深入Spring Boot (十五):web.xml去哪了

根据上面对javax.servlet.ServletContainerInitializer接口分析可知,SpringServletContainerInitializer的onStartup方法会在web应用启动的时候被调用。在分析onStartup方法之前,关注到SpringServletContainerInitializer类上使用@HandlesTypes注解标注,这个注解的value是WebApplicationInitializer,所以,支持Servlet3.0+的容器在启动时会自动扫描classpath下WebApplicationInitializer接口的实现类,并将这些实现类传递给onStartup方法的第一个参数。

深入Spring Boot (十五):web.xml去哪了

上面代码做了简单的注释,可以看到onStartup会遍历执行WebApplicationInitializer接口实现类的onStartup方法。现在,我们在回过来看一下AbstractAnnotationConfigDispatcherServletInitializer类结构。

深入Spring Boot (十五):web.xml去哪了

深入Spring Boot (十五):web.xml去哪了

深入Spring Boot (十五):web.xml去哪了

AbstractAnnotationConfigDispatcherServletInitializer继承自AbstractDispatcherServletInitializer,而AbstractDispatcherServletInitializer又继承自AbstractContextLoaderInitializer,AbstractContextLoaderInitializer实现了WebApplicationInitializer接口,所以AbstractAnnotationConfigDispatcherServletInitializer子类的onStartup方法会在web应用启动的时候被调用,创建DispatcherServlet和ContextLoaderListener,进而创建Spring上下文,完成应用初始化操作。

SpringBoot不再使用web.xml

=====================

既然Spring框架从3.1开始逐步使用Java Config替换web.xml,那么SpringBoot作为快速、简便使用Spring框架的脚手架,必然也不会再继续使用web.xml了。

在基于SpringBoot开发的代码中依然可以继续使用servlet-api中javax.servlet.annotation包中新增的@WebServlet、@WebFilter和@WebListener注解,用于简化Servlet、过滤器和监听器的声明,不过需要注意别忘记使用SpringBoot提供的@ServletComponentScan注解开启对这三注解的扫描。

SpringBoot提供了ServletRegistrationBean、FilterRegistrationBean和ServletListenerRegistrationBean,用于动态注册Servlet、过滤器和监听器,例如如下代码。

深入Spring Boot (十五):web.xml去哪了

上面代码虽然创建了三个bean,但这三个bean仅托管到了Spring上下文中,并没有注册到ServletContext中,那什么时候被注册到ServletContext中呢?查看ServletRegistrationBean、FilterRegistrationBean和ServletListenerRegistrationBean源码会发现,它们都间接继承自RegistrationBean,而RegistrationBean实现了ServletContextInitializer接口。

深入Spring Boot (十五):web.xml去哪了

注意看RegistrationBean实现的是ServletContextInitializer接口,它是SpringBoot提供的接口,和我们上面说到的ServletContainerInitializer接口不是同一个,一定不要混淆。ServletContextInitializer接口使用编程的方式配置Servlet3.0+的ServletContext,它不会被Servlet容器启动时自动调用,它的生命周期由Spring管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值