Java EE - Servlet 3.0 和 Spring MVC
Table of Contents
- 前言
- 基于 Java 的配置
- ServletContainerInitializer
- 动态配置
- DispatcherServlet 和 ContextLoaderListener
- 两个应用上下文
- 配置过程
- 结语
- 参考链接
前言
在学习 Spring MVC 的过程中发现,Spring MVC 使用了不少 Servlet 3.0 的新特性,但鉴于我学习 Servlet 使用的教程是 《Head First Servlet & JSP》,其中的 Servlet 版本只有 2.5,因此不得不去研究一下 Servlet 3.0 的新特性在继续 Spring MVC 的学习。
这篇博客的主要内容便是在学习了 Servlet 3.0 的一些新特性之后对 Spring MVC 的启动配置过程的理解。
注意:博客的主要内容不是关于 Servlet 3.0 的新特性和 Spring MVC 的使用的。
Servlet 3.0 规范 2009 年就出来了,但是现在的教程基本上还是从 web.xml 开始配置的……
基于 Java 的配置
首先我们来看一下一个基于 Java 的配置,其实就是《Spring 实战》第五章的那个配置:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import spittr.web.WebConfig;
public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
这个配置的作用为:
- 配置 DispatcherServlet 的路径映射为
/
, 也就是说所有的请求都会经由 DispatcherServlet 进行处理 - 指定 DispatcherServlet 中的应用上下文配置类为 WebConfig
- 指定 ContextLoaderListener 中的应用上下文配置类为 RootConfig
由于在看 《Head First Servlet & JSP》的时候配置都是基于 XML 的,因此在看到《Spring 实战》的这一部分的时候我产生了不少的疑惑,其中包括:
- DispatcherServlet 是什么?是我们自己编写的 Servlet 还是 Spring MVC 自带的?
- ContextLoaderListener 是什么?新种类的 Listener?
- 我没有在 DD 中配置 DispatcherServlet,Servlet 容器怎么知道把请求发送给 DispatcherServlet?
- Spring MVC 中存在两个应用上下文?
- 基于 XML 又该怎样配置?
- ……
这里面的一些问题可以通过看书解决,但有一些问题,还是需要查阅网上的资料才行。
ServletContainerInitializer
Servlet 3.0 中的新特性还是不少的,其中一个新特性便是:
- 在 Servlet 3.0 环境中,Servlet 容器会在类路径中查找实现了 ServletContainerInitializer 接口的类,如果能发现的话,就会在启动的时候自动调用实现类的 onStartup 方法1。
Spring MVC 中的 ServletContainerInitializer 实现便是 SpringServletContainerInitializer,它的部分源码如下:
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
// ...
}
}
onStartup 中的代码可以不用管,关键在于 SpringServletContainerInitializer 头上的那个注解:
@HandlesTypes(WebApplicationInitializer.class)
这个注解的意思是:初始化 SpringServletContainerInitializer 时扫描所有实现了 WebApplicationInitializer 接口的类,并作为参数 webAppInitializerClasses 传递给 onStartup 方法。
而我们在前面的配置中继承的 AbstractAnnotationConfigDispatcherServletInitializer 便是 WebApplicationInitializer 的一个便利的基础实现。
也就是说,Servlet 容器启动的时候会将我们的配置类发送给 SpringServletContainerInitializer 方法,然后在进行一系列的操作后完成 DispatcherServlet 的配置。
到了这里,大概能解决 Servlet 容器是怎么找到我们的配置类的,但还有一个问题是:Spring MVC 是怎么配置的 DispatcherServlet。
动态配置
Servlet 3.0 中的一个新特性便是支持动态配置,我们可以通过 ServletContext 获取 Registration 对象进行动态配置,比如:
ServletRegistration.Dynamic registratio = ServletContext.addServlet("appServlet", DispatcherServlet.class);
registratio.addMapping("/");
我们可以看到,SpringServletContainerInitializer 的 onStartup 是可以获得 ServletContext 的,因此,我们完全可以在 onStartup 内部完成 DispatcherServlet 的配置。
很好,Servlet 容器是怎么配置 DispatcherServlet 的问题大概可以解决了。
DispatcherServlet 和 ContextLoaderListener
通过查阅资料可以发现,DispatcherServlet 是 Spring MVC 框架自带的 Servlet,而 ContextLoaderListener 是 Spring MVC 自带的 ServletContextListener,不是新品种的监听者。
这两个类的源码链接如下:
- spring-framework/ContextLoaderListener.java at master · spring-projects/spring-framework
- spring-framework/DispatcherServlet.java at master · spring-projects/spring-framework
两个应用上下文
在最开始的配置中,我们分别制定了 DispatcherServlet 和 ContextLoaderListener 中的应用上下文的配置类,这意味着:
- Spring MVC 中存在两个应用上下文,这两个应用上下文分别位于 DispatcherServlet 和 ContextLoaderListener
翻书可以得知,这两个应用上下文的作用分别为:
- DispatcherServlet 应用上下文用于加载应用中包含 Web 组件的 Bean,包括控制器、视图解析器……
- ContextLoaderListener 应用上下文用于加载应用中的其他 Bean,通常是驱动应用后端的中间层和数据层组件。
这样一来,我们便可以大致总结一下配置 DispatcherServlet 和 ContextLoaderListener 中需要配置的内容了:
- DispatcherServlet:普通 Servlet 对象需要的配置项,如路径映射、初始化参数。以及内部的 Spring 应用上下文的配置
- ContextLoaderListener:常规的应用上下文配置,比如初始化参数。以及内部的 Spring 应用上下文的配置。
配置过程
现在可以大致总结一下 Spring MVC 的配置过程了:
- Servlet 容器启动的时候查找 ServletContainerInitializer 的实现类,找到 SpringServletContainerInitializer
- 根据 SpringServletContainerInitializer 的 HandlesTypes 查找所有 WebApplicationInitializer 的实现类
- SpringServletContainerInitializer 的 onStartup 在内部的调用流程中创建并配置 DispatcherServlet 和 ContextLoaderListener
当然了,没有看源码的话,还有一个细节是不清楚的:
- 应用上下文的创建是在 DispatcherServlet 和 ContextLoaderListener 内部完成的还是在外部创建好后传递给 DispatcherServlet 和 ContextLoaderListener
当然了,这无伤大雅 ( ̄▽ ̄)
之前还一直在想 Servlet 容器是先调用 ServletContainerInitializer 还是先调用 ServletContextListener,然后突然翻译过来,我都没有配置 Listener,
那肯定只能是 ServletContainerInitializer 了啊 (°∀°)ノ
更新:
- 2019.05.11 - 看了一下官方文档,两个应用上下文都是在创建好以后再分配给 DispatcherServlet 和 ContextLoaderListener 的,同时 DispatcherServlet 中的应用上下文是 ContextLoaderListener 的子应用上下文,当 DispatcherServlet 中找不到需要的 Bean 时,就会委托给 ContextLoaderListener 应用上下文查找。
结语
本来还说贴一下 XML 的配置代码,结果《Spring 实战》提供的样例代码中直接把 web.xml 给去了,所以……
参考链接
- 通过 ServletContainerInitializer 注册 Servlet 对象 - Elim 的博客 - ITeye 博客
- JavaEE 6 Servlet 3.0 中的新特性 - Oracle
- Servlet 3.0 新特性详解
Footnotes
1 书上这里说的是:如果能发现的话,就会用实现类来配置 Servlet 容器。感觉这种说法挺不准确的,不知道是不是翻译的锅。
Java EE - Servlet 3.0 和 Spring MVC的更多相关文章
- 关于 tomcat nio connector, servlet 3.0 async, spring mvc async 的关系
tomcat 的 org.apache.coyote.http11.Http11NioProtocol Connector 是一个使用 Java NIO 实现的异步 accept 请求的 connec ...
- Ed Burns谈HTTP/2和Java EE Servlet 4规范
在2015年JavaLand大会上,Ed Burns展示了Java EE Servlet 4.0规范(JSR 369)的概要,演讲的重点在于Java EE平台对HTTP/2的支持.HTTP/2旨在解决 ...
- SpringMVC(八):使用Servlet原生API作为Spring MVC hanlder方法的参数
在SpringMVC开发中,是有场景需要在Handler方法中直接使用ServletAPI. 在Spring MVC Handler的方法中都支持哪些Servlet API作为参数呢? --Respo ...
- JAVA入门教程 - idea 新建maven spring MVC项目
用的是Idea2017版本.其他大同小异 1.新建项目 2.勾选Create from archetype 选中maven-archetype-webapp 3.输入项目名字. 4.下一步 5.点Fi ...
- java web开发入门六(spring mvc)基于intellig idea
spring mvc ssm=spring mvc+spring +mybatis spring mvc工作流程 1A)客户端发出http请求,只要请求形式符合web.xml文件中配置的*.actio ...
- 【Java面试】说说你对Spring MVC的理解
一个工作了7年的粉丝,他说在面试之前,Spring这块的内容准备得很充分. 而且各种面试题也刷了,结果在面试的时候,面试官问:"说说你对Spring MVC的理解". 这个问题一下 ...
- Java EE - Servlet 小结
Table of Contents 前言 Servlet 的生命周期 Servlet 的初始化 ServletContext & ServletConfig 请求的处理 HttpServlet ...
- Java 之 Servlet 3.0
Servlet 3.0 好处: 支持注解配置,不需要 web.xml 文件了. 步骤: (1)创建 Java EE 项目,注意:JavaEE 版本必须6.0以上才支持Servlet3.0,可以不创建 ...
- Java EE Servlet相关的两个包
Servlet in Java EE 在Java EE的规范API中(链接),Servlet相关联的最重要的两个Package为: 1.javax.servlet 包含了一系列接口和类,他们在一个Se ...
随机推荐
- Myeclipse连接数据库删除数据库(JDBC)
package com.test.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Pr ...
- 关于如何将html中的表格下载成csv格式的方法
今天在网上看了很多方法,自己还是慢慢探索写出了最终效果 简单代码如下: <!DOCTYPE html> <html> <head> <meta content ...
- MapReduce的编程思想(1)
MapReduce的编程思想(1) MapReduce的过程(2) 1. MapReduce采用分而治之的思想,将数据处理拆分为主要的Map(映射)与Reduce(化简)两步,MapReduce操作数 ...
- javascript对象的学习
一.对象的定义: 对象是JavaScript的一个基本数据类型,是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值.即属性的无序集合. JavaScript 提供多个内建对 ...
- 洛谷 P2827 蚯蚓
题目描述 本题中,我们将用符号\lfloor c \rfloor⌊c⌋表示对c向下取整,例如:\lfloor 3.0 \rfloor= \lfloor 3.1 \rfloor=\lfloor 3.9 ...
- SAP公有云和私有云解决方案概述
SAP公有云解决方案见下图最右侧,比较著名的有SAP SuccessFactors和SAP Cloud for Customer(C4C)等,作为SAP软件即服务(SaaS)的解决方案. 而最左侧的S ...
- UVA 246 10-20-30 10-20-30游戏 模拟+STL双端队列deque
Input Each input set consists of a sequence of 52 integers separated by spaces and/or ends of line. ...
- coredata栈
上下文包含所有信息 NSManagedObjectModel The NSManagedObjectModel instance describes the data that is going to ...
- Python SciPy Sparse模块学习笔记
1. sparse模块的官方document地址:http://docs.scipy.org/doc/scipy/reference/sparse.html 2. sparse matrix的存储 ...
- springmvc的第一个程序
文中用的框架版本:spring 3,hibernate 3,没有的,自己上网下. web.xml配置: <?xml version="1.0" encoding=" ...