@ -1,35 +1,36 @@
## 1 SpringMVC应用场景
## 1 SpringMVC应用场景
在使用SpringMVC时, 除了要在web.xml中配置ContextLoaderListener外, 还要对DispatcherServlet进行配置。作为一个Servlet, 这个DispatcherServlet实现的是Sun的J2EE核心模式中的前端控制器模式(Front Controller), 作为一个前端控制器, 所有的Web请求都需要通过它来处理, 进行转发、匹配、数据处理后,并 转由页面进行展现, 因此这个DispatcerServlet可以看成是Spring MVC实现中最为核心的部分。
在使用 SpringMVC 时,除了要在 web.xml 中配置 ContextLoaderListener 外,还要对 DispatcherServlet 进行配置。作为一个 Servlet, 这个 DispatcherServlet 实现的是 Sun 的 J2EE核心模式 中的 前端控制器模式(Front Controller), 作为一个前端控制器,所有的 Web请求 都需要通过它来进行转发、匹配、数据处理,然 后转由页面进行展现,因此这个 DispatcerServlet 可以看成是 SpringMVC实现 中最为核心的部分。
在Spring MVC中, 对于不同的Web请求的映射需求, Spring MVC提供了不同的HandlerMapping的实现, 可以让应用开发选取不同的映射策略。DispatcherSevlet默认了BeanNameUrlHandlerMapping作为映射策略实现。除了映射策略可以定制外, Spring MVC提供了各种Controller的实现来供应用扩展和使用, 以应对不同的控制器使用场景, 这些Controller控制器需要实现handleRequest接口方法, 并返回ModelAndView对象。Spring MVC还提供了各种视图实现, 比如常用的JSP视图。除此之外, Spring MVC还提供了拦截器供应用使用, 允许应用对Web请求进行拦截, 以及前置处理和后置处理。
在 SpringMVC 中,对于不同的 Web请求 的映射需求, SpringMVC 提供了不同的 HandlerMapping 的实现, 可以让应用开发选取不同的映射策略。DispatcherSevlet 默认了 BeanNameUrlHandlerMapping 作为映射策略实现。除了映射策略可以定制外, SpringMVC 还 提供了各种 Controller 的实现来供应用扩展和使用,以应对不同的控制器使用场景,这些 Controller控制器 需要实现 handleRequest() 接口方法,并返回 ModelAndView对象。SpringMVC 还提供了各种视图实现,比如常用的 JSP视图。除此之外, SpringMVC 还提供了拦截器供应用使用,允许应用对 Web请求 进行拦截,以及前置处理和后置处理。
## 2 SpringMVC设计概览
## 2 SpringMVC设计概览
在完成对ContextLoaderListener的初始化以后, Web容器开始初始化DispatcherServlet, 这个初始化的启动与在web.xml中对载入次序的定义有关。DispatcherServlet会建立自己的上下文来持有Spring MVC的Bean对象, 在建立这个自己持有的IoC容器时, 会**从ServletContext中得到根上下文**作为DispatcherServlet持有上下文的双亲上下文。有了这个根上下文, 再对自己持有的上下文进行初始化, 最后把自己持有的这个上下文保存到ServletContext中, 供以后检索和使用。
在完成对 ContextLoaderListener 的初始化以后, Web容器 开始初始化 DispatcherServlet, 这个初始化的启动与在 web.xml 中对载入次序的定义有关。DispatcherServlet 会建立自己的上下文来持有SpringMVC 的 Bean对象, 在建立这个自己持有的 IoC容器 时,会**从 ServletContext 中得到根上下文**作为 DispatcherServlet 持有上下文的双亲上下文。有了这个根上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文保存到 ServletContext 中,供以后检索和使用。
为了解这个过程, 可以从DispatcherServlet的父类FrameworkServlet的代码入手, 去探寻DispatcherServlet的启动过程, 它同时也是SpringMVC的启动过程。ApplicationContext的创建过程和ContextLoader创建根上下文的过程有许多类似的地方。下面来看一下这个DispatcherServlet类的继承关系。
为了解这个过程,可以从 DispatcherServlet 的父类 FrameworkServlet 的代码入手,去探寻 DispatcherServlet 的启动过程,它同时也是 SpringMVC 的启动过程。ApplicationContext 的创建过程和 ContextLoader 创建根上下文的过程有许多类似的地方。下面来看一下这个 DispatcherServlet类 的继承关系。


DispatcherServlet通过继承FrameworkServlet和HttpServletBean而继承了HttpServlet, 通过使用Servlet API来对HTTP请求进行响应, 成为Spring MVC的前端处理器, 同时成为MVC模块与Web容器集成的处理前端。
DispatcherServlet 通过继承 FrameworkServlet 和 HttpServletBean 而继承了 HttpServlet, 通过使用Servlet API 来对 HTTP请求 进行响应,成为 SpringMVC 的前端处理器,同时成为 MVC模块 与 Web容器 集成的处理前端。
DispatcherServlet的工作大致可以分为两个部分: 一个是初始化部分, 由initServletBean()启动, 通过initWebApplicationContext()方法最终调用DispatcherServlet的initStrategies()方法, 在这个方法里, DispatcherServlet对MVC模块的其他部分进行了初始化, 比如handlerMapping、ViewResolver等; 另一个是对HTTP请求进行响应, 作为一个Servlet, Web容器会调用Servlet的doGet()和doPost()方法, 在经过FrameworkServlet的processRequest()简单处理后, 会调用DispatcherServlet的doService()方法, 在这个方法调用中封装了doDispatch(), 这个doDispatch()是Dispatcher实现MVC模式的主要部分, 下图为DispatcherServlet的处理过程时序图。
DispatcherServlet 的工作大致可以分为两个部分:一个是初始化部分,由 initServletBean()方法 启动,通过 initWebApplicationContext()方法 最终调用 DispatcherServlet 的 initStrategies()方法, 在这个方法里, DispatcherServlet 对 MVC模块 的其他部分进行了初始化,比如 handlerMapping、ViewResolver 等;另一个是对 HTTP请求 进行响应,作为一个 Servlet, Web容器 会调用 Servlet 的doGet() 和 doPost()方法,在经过 FrameworkServlet 的 processRequest() 简单处理后,会调用 DispatcherServlet 的 doService()方法,在这个方法调用中封装了 doDispatch(),这个 doDispatch() 是 Dispatcher 实现 MVC模式 的主要部分,下图为 DispatcherServlet 的处理过程时序图。


## 3 DispatcherServlet的启动和初始化
## 3 DispatcherServlet的启动和初始化
前面大致描述了Spring MVC的工作流程, 下面看一下DispatcherServlet的启动和初始化的代码设计及实现。
前面大致描述了 SpringMVC 的工作流程,下面看一下 DispatcherServlet 的启动和初始化的代码设计及实现。
作为Servlet, DispatcherServlet的启动与Servlet的启动过程是相联系的。在Servlet的初始化过程中, Servlet的init()方法会被调用, 以进行初始化, DispatcherServlet的基类HttpServletBean实现了该方法。在初始化开始时, 需要读取配置在ServletContext中的Bean属性参数, 这些属性参数设置在web.xml的Web容器初始化参数中。使用编程式的方式来设置这些Bean属性, 在这里可以看到对PropertyValues和BeanWrapper的使用。对于这些和依赖注人相关的类的使用, 在分析IoC容器的初始化时, 尤其是在依赖注入实现分析时, 有过“亲密接触”。只是这里的依赖注人是与Web容器初始化相关的。
作为 Servlet, DispatcherServlet 的启动与 Servlet 的启动过程是相联系的。在 Servlet 的初始化过程中, Servlet 的 init()方法 会被调用, 以进行初始化, DispatcherServlet 的基类 HttpServletBean 实现了该方法。在初始化开始时,需要读取配置在 ServletContext 中的 Bean属性参数, 这些属性参数设置在 web.xml 的 Web容器初始化参数 中。使用编程式的方式来设置这些 Bean属性, 在这里可以看到对 PropertyValues 和 BeanWrapper 的使用。对于这些和依赖注人相关的类的使用,在分析 IoC容器 的初始化时,尤其是在依赖注入实现分析时,有过“亲密接触”。只是这里的依赖注人是与 Web容器 初始化相关的。
接着会执行DispatcherServlet持有的IoC容器的初始化过程, 在这个初始化过程中, 一个新的上下文被建立起来, 这个DispatcherServlet持有的上下文被设置为根上下文的子上下文。一个Web应用中可以容纳多个Servlet存在; 与此相对应, 对于应用在Web容器中的上下体系, 一个根上下文可以作为许多Servlet上下文的双亲上下文。了解IoC工作原理的读者知道, 在向IoC容器getBean()时, IoC容器会首先向其双亲上下文去getBean(), 也就是说, 在根上下文中定义的Bean是可以被各个Servlet持有的上下文得到和共享的。DispatcherServlet持有的 上下文被建立起来以后, 也需要和其他IoC容器一样完成初始化, 这个初始化也是通过refresh()方法来完成的。最后, DispatcherServlet给这个自己持有的上下文命名, 并把它设置到Web容器的上下文中, 这个名称和在web.xml中设置的DispatcherServlet的Servlet名称有关, 从而保证了这个上下文在Web环境上下文体系中的唯一性。
接着会执行 DispatcherServlet 持有的 IoC容器 的初始化过程,在这个初始化过程中,一个新的上下文被建立起来,这个 DispatcherServlet 持有的上下文被设置为根上下文的子上下文。一个 Web应用 中可以容纳多个 Servlet 存在;与此相对应,对于应用在 Web容器 中的上下体系,一个根上下文可以作为许多 Servlet上下文 的双亲上下文。了解 IoC 工作原理的读者知道,在向 IoC容器 getBean() 时, IoC容器 会首先向其双亲上下文去 getBean(),也就是说,在根上下文中定义的 Bean 是可以被各个 Servlet 持有的上下文得到和共享的。DispatcherServlet 持有的 上下文被建立起来以后,也需要和其他 IoC容器 一样完成初始化,这个初始化也是通过 refresh()方法 来完成的。最后, DispatcherServlet 给这个自己持有的上下文命名,并把它设置到 Web容器 的上下文中,这个名称和在 web.xml 中设置的 DispatcherServlet 的 Servlet名称 有关,从而保证了这个上下文在 Web环境上下文体系 中的唯一性。
```java
```java
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
public final void init() throws ServletException {
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
logger.debug("Initializing servlet '" + getServletName() + "'");
}
}
// 获取Servlet的初始化参数, 对bean属性进行配置
// 获取 Servlet 的初始化参数,对 bean属性 进行配置
try {
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
@ -54,10 +55,11 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
public abstract class FrameworkServlet extends HttpServletBean {
public abstract class FrameworkServlet extends HttpServletBean {
/** 此servlet的WebApplicationContext */
/** 此 servlet 的 WebApplicationContext */
private WebApplicationContext webApplicationContext;
private WebApplicationContext webApplicationContext;
/** 我们是否应该将当前Servlet的上下文webApplicationContext设为ServletContext的属性 */
/** 我们是否应该将当前 Servlet 的上下文 webApplicationContext 设为 ServletContext 的属性 */
private boolean publishContext = true;
private boolean publishContext = true;
public FrameworkServlet() {
public FrameworkServlet() {
@ -68,7 +70,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
/**
/**
* 覆盖了父类HttpServletBean的空实现
* 覆盖了父类 HttpServletBean 的空实现
*/
*/
@Override
@Override
protected final void initServletBean() throws ServletException {
protected final void initServletBean() throws ServletException {
@ -100,16 +102,16 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
/**
/**
* 为这个Servlet初始化一个公共的WebApplicationContext实例
* 为这个 Servlet 初始化一个公共的 WebApplicationContext实例
*/
*/
protected WebApplicationContext initWebApplicationContext() {
protected WebApplicationContext initWebApplicationContext() {
// 获取 根上下文 作为当前MVC上下文的双亲上下文, 这个根上下文保存在ServletContext中
// 获取根上下文作为当前 MVC上下文 的双亲上下文,这个根上下文保存在 ServletContext 中
WebApplicationContext rootContext =
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
if (this.webApplicationContext != null) {
// 可以在本对象被构造时注入一个webApplicationContext实例
// 可以在本对象被构造时注入一个 webApplicationContext实例
wac = this.webApplicationContext;
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
@ -126,24 +128,24 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
if (wac == null) {
if (wac == null) {
// 在本对象被构造时没有注入上下文实例 ->
// 在本对象被构造时没有注入上下文实例 ->
// 查看是否已在servlet上下文中注册了上下文实例。
// 查看是否已在 servlet上下文 中注册了上下文实例。
// 如果存在一个,则假定父上下文(如果有的话)已经被设置,
// 如果存在一个,则假定父上下文(如果有的话)已经被设置,
// 并且用户已经执行了任何初始化, 例如设置上下文ID
// 并且用户已经执行了任何初始化, 例如设置上下文ID
wac = findWebApplicationContext();
wac = findWebApplicationContext();
}
}
if (wac == null) {
if (wac == null) {
// 没有为此servlet定义上下文实例 -> 创建本地实例
// 没有为此 servlet 定义上下文实例 -> 创建本地实例
wac = createWebApplicationContext(rootContext);
wac = createWebApplicationContext(rootContext);
}
}
if (!this.refreshEventReceived) {
if (!this.refreshEventReceived) {
// 上下文 不是支持刷新的ConfigurableApplicationContext, 或者
// 上下文不是支持刷新的 ConfigurableApplicationContext, 或者
// 在构造时注入的上下文已经完成刷新 -> 在此处手动触发onRefresh()方法
// 在构造时注入的上下文已经完成刷新 -> 在此处手动触发 onRefresh()方法
onRefresh(wac);
onRefresh(wac);
}
}
if (this.publishContext) {
if (this.publishContext) {
// 把当前建立的上下文保存到ServletContext中, 使用的属性名是和当前servlet名相关的
// 把当前建立的上下文保存到 ServletContext 中,使用的属性名是和 当前servlet名 相关的
String attrName = getServletContextAttributeName();
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
if (this.logger.isDebugEnabled()) {
@ -156,7 +158,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
}
}
```
```
至此, 这个MVC的上下文就建立起来了, 具体取得根上下文的过程在WebApplicationContextUtils中实现。这个根上下文是ContextLoader设置到ServletContext中去的, 使用的属性是ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ContextLoader还对这个IoC容器的Bean配置文件进行了设置, 默认的位置是在/WEB-INF/applicationContext.xml文件中。由于这个根上下文是DispatcherServlet建立的上下文的 双亲上下文, 所以根上下文中管理的Bean也可以被DispatcherServlet的上下文使用。通过getBean()向IoC容器获取Bean时, 容器会先到它的双亲IoC容器中获取。
至此,这个 MVC 的上下文就建立起来了,具体取得根上下文的过程在 WebApplicationContextUtils 中实现。这个根上下文是 ContextLoader 设置到 ServletContext 中去的,使用的属性是 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ContextLoader 还对这个 IoC容器 的 Bean 配置文件进行了设置,默认的位置是在 /WEB-INF/applicationContext.xml文件 中。由于这个根上下文是 DispatcherServlet 建立的上下文的 双亲上下文,所以根上下文中管理的 Bean 也可以被 DispatcherServlet 的上下文使用。通过 getBean() 向 IoC容器 获取 Bean 时,容器会先到它的 双亲IoC容器 中获取。
```java
```java
/**
/**
* 这是一个封装了很多静态方法的抽象工具类,所以只能调用其静态方法,
* 这是一个封装了很多静态方法的抽象工具类,所以只能调用其静态方法,
@ -164,8 +166,8 @@ public abstract class FrameworkServlet extends HttpServletBean {
*/
*/
public abstract class WebApplicationContextUtils {
public abstract class WebApplicationContextUtils {
/**
/**
* 使用了WebApplicationContext的ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性, 获取
* 使用了 WebApplicationContext 的 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性, 获取
* ServletContext中的根上下文, 这个属性代表的根上下文在ContextLoaderListener初始化的
* ServletContext 中的根上下文,这个属性代表的根上下文在 ContextLoaderListener 初始化的
* 过程中被建立
* 过程中被建立
*/
*/
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
@ -173,7 +175,7 @@ public abstract class WebApplicationContextUtils {
}
}
/**
/**
* 查找此web应用程序的自定义WebApplicationContext
* 查找此 web应用程序 的自定义 WebApplicationContext
*/
*/
public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
Assert.notNull(sc, "ServletContext must not be null");
Assert.notNull(sc, "ServletContext must not be null");
@ -197,20 +199,20 @@ public abstract class WebApplicationContextUtils {
}
}
)
)
```
```
回到FrameworkServlet的实现中来看一下, DispatcherServlet的上下文是怎样建立的, 这个建立过程与前面建立根上下文的过程非常类似。建立DispatcherServlet的上下文, 需要把根上下文作为参数传递给它。然后使用反射技术来实例化上下文对象, 并为它设置参数。根据默认的配置, 这个上下文对象也是XmlWebApplicationContext对象, 这个类型是在DEFAULT_CONTEXT_CLASS参数中设置好并允许BeanUtilis使用的。在实例化结束后, 需要为这个上下文对象设置好一些基本的配置, 这些配置包括它的双亲上下文、Bean配置文件的位置等。完成这些配置以后, 最后通过调用IoC容器的refresh()方法来完成IoC容器的最终初始化, 这和前面我们对IoC容器实现原理的分析中所看到的IoC容器初始化的过程是一致的。
回到 FrameworkServlet 的实现中来看一下, DispatcherServlet 的上下文是怎样建立的,这个建立过程与前面建立根上下文的过程非常类似。建立 DispatcherServlet 的上下文,需要把根上下文作为参数传递给它。然后使用反射技术来实例化上下文对象,并为它设置参数。根据默认的配置,这个上下文对象也是 XmlWebApplicationContext对象, 这个类型是在 DEFAULT_CONTEXT_CLASS参数 中设置好并允许 BeanUtilis 使用的。在实例化结束后, 需要为这个上下文对象设置好一些基本的配置, 这些配置包括它的双亲上下文、Bean配置文件 的位置等。完成这些配置以后,最后通过调用 IoC容器 的 refresh()方法 来完成 IoC容器 的最终初始化,这和前面我们对 IoC容器实现原理 的分析中所看到的 IoC容器初始化 的过程是一致的。
```java
```java
public abstract class FrameworkServlet extends HttpServletBean {
public abstract class FrameworkServlet extends HttpServletBean {
/**
/**
* 为此servlet实例化一个WebApplicationContext, 可以是默认的XmlWebApplicationContext,
* 为此 servlet 实例化一个 WebApplicationContext, 可以是默认的 XmlWebApplicationContext,
* 也可以是用户设置的自定义Context上下文
* 也可以是用户设置的自定义 Context上下文
*/
*/
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
return createWebApplicationContext((ApplicationContext) parent);
return createWebApplicationContext((ApplicationContext) parent);
}
}
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
// 默认为XmlWebApplicationContext.class
// 默认为 XmlWebApplicationContext.class
Class< ?> contextClass = getContextClass();
Class< ?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
this.logger.debug("Servlet with name '" + getServletName() +
@ -228,11 +230,11 @@ public abstract class FrameworkServlet extends HttpServletBean {
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setEnvironment(getEnvironment());
// 这里设置的 双亲上下文, 就是在ContextLoader中建立的根上下文
// 这里设置的 双亲上下文,就是在 ContextLoader 中建立的根上下文
wac.setParent(parent);
wac.setParent(parent);
wac.setConfigLocation(getContextConfigLocation());
wac.setConfigLocation(getContextConfigLocation());
// 配置并且刷新wac
// 配置并且刷新 WebApplicationContext对象
configureAndRefreshWebApplicationContext(wac);
configureAndRefreshWebApplicationContext(wac);
return wac;
return wac;
@ -240,15 +242,15 @@ public abstract class FrameworkServlet extends HttpServletBean {
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// 应用程序上下文id仍设置为其原始默认值, 如果该id不为空的话
// 应用程序上下文id 仍设置为其原始默认值,如果该 id 不为空的话
if (this.contextId != null) {
if (this.contextId != null) {
wac.setId(this.contextId);
wac.setId(this.contextId);
}
}
else {
else {
// 生成默认的id
// 生成默认的 id
ServletContext sc = getServletContext();
ServletContext sc = getServletContext();
if (sc.getMajorVersion() == 2 & & sc.getMinorVersion() < 5 ) {
if (sc.getMajorVersion() == 2 & & sc.getMinorVersion() < 5 ) {
// 当Servlet< =2.4: 如果有, 请使用web.xml中指定的名称。
// 当 Servlet < = 2.4:如果有,请使用 web.xml 中指定的名称。
String servletContextName = sc.getServletContextName();
String servletContextName = sc.getServletContextName();
if (servletContextName != null) {
if (servletContextName != null) {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +
@ -259,7 +261,7 @@ public abstract class FrameworkServlet extends HttpServletBean {
}
}
}
}
else {
else {
// Servlet 2.5的getContextPath可用!
// Servlet 2.5 的 getContextPath 可用!
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName());
ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName());
}
}
@ -272,8 +274,8 @@ public abstract class FrameworkServlet extends HttpServletBean {
wac.setNamespace(getNamespace());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// 在刷新上下文的任何情况下,都将会调用wac环境的 initPropertySources()方法。
// 在刷新上下文的任何情况下,都将会调用 此wac 的 env的 initPropertySources()方法。
// 在此处执行此方法, 以确保在刷新上下文之前, servlet属性源已准备就绪
// 在此处执行此方法, 以确保在刷新上下文之前, servlet属性源 已准备就绪
ConfigurableEnvironment env = wac.getEnvironment();
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(), getServletConfig());
((ConfigurableWebEnvironment)env).initPropertySources(getServletContext(), getServletConfig());
@ -283,20 +285,20 @@ public abstract class FrameworkServlet extends HttpServletBean {
applyInitializers(wac);
applyInitializers(wac);
// IoC容器都是通过该方法完成 容器初始化的
// IoC容器 都是通过该方法完成 容器初始化的
wac.refresh();
wac.refresh();
}
}
}
}
```
```
这时候DispatcherServlet中的IoC容器已经建立起来了, 这个IoC容器是 根上下文 的子容器。如果要查找一个由DispatcherServlet所持有的IoC容器来管理的Bean, 系统会首先到 根上下文 中去查找。如果查找不到, 才会到DispatcherServlet所管理的IoC容器去进行查找, 这是由IoC容器getBean()的实现来决定的。通过一系列在Web容器中执行的动作, 在这个上下文体系建立和初始化完毕的基础上, Spring MVC就可以发挥其作用了。下面来分析一下Spring MVC的具体实现。
这时候 DispatcherServlet 中的 IoC容器 已经建立起来了,这个 IoC容器 是 根上下文 的子容器。如果要查找一个由 DispatcherServlet 所持有的 IoC容器 来管理的 Bean, 系统会首先到 根上下文 中去查找。如果查找不到,才会到 DispatcherServlet 所管理的 IoC容器 去进行查找,这是由 IoC容器 的 getBean() 的实现来决定的。通过一系列在 Web容器 中执行的动作, 在这个上下文体系建立和初始化完毕的基础上, SpringMVC 就可以发挥其作用了。下面来分析一下 SpringMVC 的具体实现。
在前面分析DispatchServlet的初始化过程中可以看到, DispatchServlet持有一个以自己的Servlet名称命名的IoC容器。这个IoC容器是一个WebApplicationContext对象, 这个IoC容器建立起来以后, 意味着DispatcherServlet拥有自己的Bean定义空间, 这为使用各个独立的XML文件来配置MVC中各个Bean创造了条件。由于在初始化结束以后, 与Web容器相关的加载过程实际上已经完成了, SpringMVC的具体实现和普通的Spring应用程序的实现并没有太大的差别。
在前面分析 DispatchServlet 的初始化过程中可以看到, DispatchServlet 持有一个以自己的 Servlet名称 命名的 IoC容器。这个 IoC容器 是一个 WebApplicationContext对象, 这个 IoC容器 建立起来以后,意味着 DispatcherServlet 拥有自己的 Bean定义空间, 这为使用各个独立的 XML文件 来配置 MVC 中各个 Bean 创造了条件。由于在初始化结束以后,与 Web容器 相关的加载过程实际上已经完成了, SpringMVC 的具体实现和普通的 Spring应用程序 的实现并没有太大的差别。
在DispatcherServlet的初始化过程中, 以对HandlerMapping的初始化调用作为触发点, 了解SpringMVC模块初始化的方法调用关系。这个调用关系最初是由HttpServletBean的init()方法触发的, 这个HttpServletBean是HttpServlet的子类。接着会在HttpServletBean的子类FrameworkServlet中对IoC容器完成初始化, 在这个初始化方法中, 会调用DispatcherServlet的initStrategies()方法, 该方法包括对各种MVC框架的实现元素, 比如支持国际化的LocalResolver、支持request映射的HandlerMappings, 以及视图生成的ViewResolver等。由该方法启动整个Spring MVC框架的初始化。
在 DispatcherServlet 的初始化过程中,以对 HandlerMapping 的初始化调用作为触发点,了解 SpringMVC模块 初始化的方法调用关系。这个调用关系最初是由 HttpServletBean 的 init()方法 触发的,这个 HttpServletBean 是 HttpServlet 的子类。接着会在 HttpServletBean 的子类 FrameworkServlet 中对 IoC容器 完成初始化,在这个初始化方法中,会调用 DispatcherServlet 的 initStrategies()方法,该方法包括对各种 MVC框架 的实现元素,比如支持国际化的 LocalResolver、支持 request 映射的 HandlerMappings, 以及视图生成的 ViewResolver 等。由该方法启动整个 SpringMVC框架 的初始化。
```java
```java
public class DispatcherServlet extends FrameworkServlet {
public class DispatcherServlet extends FrameworkServlet {
/**
/**
* 初始化此servlet使用的策略对象。
* 初始化此 servlet 使用的策略对象。
* 可以在子类中重写, 以便初始化进一步的策略对象( U8C)
* 可以在子类中重写, 以便初始化进一步的策略对象( U8C)
*/
*/
protected void initStrategies(ApplicationContext context) {
protected void initStrategies(ApplicationContext context) {
@ -306,7 +308,7 @@ public class DispatcherServlet extends FrameworkServlet {
initLocaleResolver(context);
initLocaleResolver(context);
// 主题view层
// 主题view层
initThemeResolver(context);
initThemeResolver(context);
// 解析url和Method的对应关系
// 解析 url 和 Method 的对应关系
initHandlerMappings(context);
initHandlerMappings(context);
// 适配器匹配
// 适配器匹配
initHandlerAdapters(context);
initHandlerAdapters(context);
@ -321,42 +323,42 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
}
}
```
```
对于具体的初始化过程, 根据上面的方法名称, 很容易理解。以HandlerMapping为例来说明这个initHandlerMappings()过程。这里的Mapping关系的作用是, 为HTTP请求找到相应的Controller控制器, 从而利用这些控制器Controller去完成设计好的数据处理工作。
对于具体的初始化过程,根据上面的方法名称,很容易理解。以 HandlerMapping 为例来说明这个 initHandlerMappings()过程。这里的 Mapping关系 的作用是,为 HTTP请求 找到相应的 Controller控制器, 从而利用这些 控制器Controller 去完成设计好的数据处理工作。
HandlerMappings完成对MVC中Controller的定义和配置, 只不过在Web这个特定的应用环境中, 这些控制器是与具体的HTTP请求相对应的。在HandlerMapping初始化的过程中, 把在Bean配置文件中配置好的HandlerMapping从IoC容器中取得。
HandlerMappings 完成对 MVC 中 Controller 的定义和配置,只不过在 Web 这个特定的应用环境中,这些控制器是与具体的 HTTP请求 相对应的。在 HandlerMapping初始化 的过程中,把在 Bean配置文件 中配置好的 HandlerMapping 从 IoC容器 中取得。
```java
```java
/**
/**
* 初始化此类使用的HandlerMappings。
* 初始化此类使用的 HandlerMappings。
* 如果在BeanFactory中没有为此命名空间定义的HandlerMapping bean, 则默认为BeanNameUrlHandlerMapping
* 如果在 BeanFactory 中没有为此命名空间定义的 HandlerMapping bean, 则默认为 BeanNameUrlHandlerMapping
*/
*/
private void initHandlerMappings(ApplicationContext context) {
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
this.handlerMappings = null;
// 这个detectAllHandlerMappings默认为true, 表示从所有的IoC容器中获取所有的HandlerMappings
// 这个 detectAllHandlerMappings 默认为 true, 表示从所有的 IoC容器 中获取所有的HandlerMappings
if (this.detectAllHandlerMappings) {
if (this.detectAllHandlerMappings) {
// 查找所有的HandlerMapping, 从应用上下文context及其双亲上下文中
// 查找所有的 HandlerMapping, 从 应用上下文context 及其双亲上下文中
Map< String , HandlerMapping > matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
Map< String , HandlerMapping > matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList< HandlerMapping > (
this.handlerMappings = new ArrayList< HandlerMapping > (
matchingBeans.values());
matchingBeans.values());
// 保持HandlerMappings的有序性
// 保持 HandlerMappings 的有序性
OrderComparator.sort(this.handlerMappings);
OrderComparator.sort(this.handlerMappings);
}
}
}
}
else {
else {
try {
try {
// 根据名称从当前的IoC容器中通过getBean()获取HandlerMapping
// 根据名称从当前的 IoC容器 中通过 getBean() 获 取HandlerMapping
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME,
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME,
HandlerMapping.class);
HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
this.handlerMappings = Collections.singletonList(hm);
}
}
catch (NoSuchBeanDefinitionException ex) {
catch (NoSuchBeanDefinitionException ex) {
// 忽略, 稍后将添加默认的HandlerMapping
// 忽略,稍后将添加默认的 HandlerMapping
}
}
}
}
// 如果找不到其他映射, 请通过注册默认的HandlerMapping确保至少有一个HandlerMapping
// 如果找不到其他映射,请通过注册默认的 HandlerMapping 确保至少有一个 HandlerMapping
if (this.handlerMappings == null) {
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
@ -366,20 +368,18 @@ HandlerMappings完成对MVC中Controller的定义和配置, 只不过在Web这
}
}
}
}
```
```
经过以上读取过程, handlerMappings变量就已经获取了在Bean中配置好的映射关系。其他的初始化过程和handlerMappings比较类似, 都是直接从IoC容器中读入配置, 所以这里的MVC初始化过程是建立在IoC容器已经初始化完成的基础上的。
经过以上读取过程, handlerMappings变量 就已经获取了在 Bean 中配置好的映射关系。其他的初始化过程和 handlerMappings 比较类似,都是直接从 IoC容器 中读入配置,所以这里的 MVC初始化过程 是建立在 IoC容器 已经初始化完成的基础上的。
## 4 SpringMVC处理分发HTTP请求
## 4 SpringMVC处理分发HTTP请求
### 4.1 HandlerMapping的配置和设计原理
### 4.1 HandlerMapping的配置和设计原理
前面分析了DispatcherServlet对Spring MVC框架的初始化过程, 在此基础上, 我们再进一步分析HandlerMapping的实现原理, 看看这个MVC框架中比较关键的控制部分是如何实现的。
前面分析了 DispatcherServlet 对 SpringMVC框架 的初始化过程,在此基础上,我们再进一步分析 HandlerMapping 的实现原理,看看这个 MVC框架 中比较关键的控制部分是如何实现的。
在初始化完成时, 在上下文环境中已定义的所有HandlerMapping都已经被加载了, 这些加载的handlerMappings被放在一个List中并被排序, 存储着HTTP请求对应的映射数据。这个List中的每一个元素都对应着一个具体handlerMapping的配置, 一般每一个handlerMapping
在初始化完成时,在上下文环境中已定义的所有 HandlerMapping 都已经被加载了,这些加载的 handlerMappings 被放在一个 List 中并被排序,存储着 HTTP请求 对应的映射数据。这个 List 中的每一个元素都对应着一个具体 handlerMapping 的配置,一般每一个 handlerMapping 可以持有一系列从 URL请求 到 Controller 的映射,而 SpringMVC 提供了一系列的 HandlerMapping 实现。
可以持有一系列从URL请求到Controller的映射, 而Spring MVC提供了一系列的HandlerMapping实现。


以SimpleUrlHandlerMapping这个handlerMapping为例来分析HandlerMapping的设计与实现。在SimpleUrlHandlerMapping中, 定义了一个map来 持有 一系列的映射关系。通过这些在HandlerMapping中定义的映射关系, 即这些URL请求和控制器的对应关系, 使Spring MVC
以 SimpleUrlHandlerMapping 为例来分析 HandlerMapping 的设计与实现。在 SimpleUrlHandlerMapping 中,定义了一个 Map 来持有一系列的映射关系。通过这些在 HandlerMapping 中定义的映射关系,即这些 URL请求 和控制器的对应关系,使 SpringMVC
应用可以根据HTTP请求确定一个对应的Controller。具体来说, 这些映射关系是通过接口HandlerMapping来封装的, 在HandlerMapping接 口中定义了一个getHandler方法, 通过这个方法, 可以获得与HTTP请求对应的HandlerExecutionChain, 在这个HandlerExecutionChain
应用 可以根据 HTTP请求 确定一个对应的 Controller。具体来说, 这些映射关系是通过 HandlerMapping接口 来封装的,在 HandlerMapping接口 中定义了一个 getHandler()方法,通过这个方法,可以获得与 HTTP请求 对应的 HandlerExecutionChain, 在这个 HandlerExecutionChain 中,封装了具体的 Controller对象。
中, 封装了具体的Controller对象。
```java
```java
public interface HandlerMapping {
public interface HandlerMapping {
@ -396,15 +396,13 @@ public interface HandlerMapping {
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
/**
/**
* 返回的这个HandlerExecutionChain不但持有handler本身, 还包括了处理这个HTTP请求的拦截器
* 返回的这个 HandlerExecutionChain 不但持有 handler本身, 还包括了处理这个 HTTP请求 的拦截器链
*/
*/
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
}
```
```
这个HandlerExecutionChain的实现看起来比较简洁, 它持有一个Interceptor链和一个handler对象, 这个handler对象实际上就是HTTP请求对应的Controller, 在持有这个handler对象的同时, 还在HandlerExecutionChain中设置了一个拦截器链, 通过这个拦截器链中的拦截器,
这个 HandlerExecutionChain 的实现看起来比较简洁,它持有一个 拦截器链(HandlerInterceptor对象列表) 和一个 handler对象, 这个 handler对象 实际上就是 HTTP请求 对应的 Controller, 在持有这个 handler对象 的同时,还在 HandlerExecutionChain 中设置了一个拦截器链,通过这个拦截器链中的拦截器,可以为 handler对象 提供功能的增强。要完成这些工作,需要对拦截器链和 handler 都进行配置,这些配置都是在 HandlerExecutionChain 的初始化函数中完成的。为了维护这个拦截器链和 handler, HandlerExecutionChain 还提供了一系列与拦截器链维护相关的操作,比如,为拦截器链增加拦截器的 addInterceptor()方法。
可以为handler对象提供功能的增强。要完成这些工作, 需要对拦截器链和handler都进行配置, 这些配置都是在HandlerExecutionChain的初始化函数中完成的。为了维护这个拦截器链和handler, HandlerExecutionChain还提供了一系列与拦截器链维护相关的操作, 比如, 为拦
截器链增加拦截器的addInterceptor()方法。
```java
```java
public class HandlerExecutionChain {
public class HandlerExecutionChain {
@ -460,7 +458,7 @@ public class HandlerExecutionChain {
}
}
/**
/**
* 延迟初始化interceptorList和interceptors集合
* 延迟初始化 interceptorList 和 interceptors集合
*/
*/
private void initInterceptorList() {
private void initInterceptorList() {
if (this.interceptorList == null) {
if (this.interceptorList == null) {
@ -496,12 +494,13 @@ public class HandlerExecutionChain {
}
}
}
}
```
```
HandlerExecutionChain中定义的Handler和Interceptor需要在定义HandlerMapping时配置好, 例如对具体的SimpleURLHandlerMapping, 要做的就是根据URL映射的方式, 注册Handler和Interceptor, 从而维护一个反映这种映射关系的handlerMap。当需要匹配HTTP请求时, 需要查询这个handlerMap中的信息来得到对应的HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程, 这个注册过程在容器对Bean进行依赖注入时发生, 它实际上是通过一个Bean的postProcessor()来完成的。以SimpleHandlerMapping为例, 需要注意的是, 这里用到了对容器的回调, 只有SimpleHandlerMapping是ApplicationContextAware的子类才能启动这个注册过程。这个注册过程完成的是反映URL和Controller之间映射关系的handlerMap的建立。
HandlerExecutionChain 中定义的 Handler 和 Handler Interceptor[]属性 需要在定义 HandlerMapping 时配置好,例如对具体的 SimpleURLHandlerMapping, 要做的就是根据 URL映射 的方式,注册 Handler 和 Handler Interceptor[] ,从而维护一个反映这种映射关系的 handlerMap。当需要匹配 HTTP请求 时,需要查询这个 handlerMap 中的信息来得到对应的 HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对 Bean 进行依赖注入时发生,它实际上是通过一个 Bean 的 postProcessor() 来完成的。以 SimpleHandlerMapping 为例,需要注意的是,这里用到了对容器的回调,只有 SimpleHandlerMapping 是 ApplicationContextAware 的子类才能启动这个注册过程。这个注册过程完成的是反映 URL 和 Controller 之间映射关系的 handlerMap 的建立。


```java
```java
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
@Override
@Override
public void initApplicationContext() throws BeansException {
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
super.initApplicationContext();
@ -509,18 +508,18 @@ public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
}
}
/**
/**
* 为相应的路径注册URL映射中指定的所有handlers处理程序
* 为相应的路径注册 URL映射 中指定的所有 handlers处理程序
*/
*/
protected void registerHandlers(Map< String , Object > urlMap) throws BeansException {
protected void registerHandlers(Map< String , Object > urlMap) throws BeansException {
if (urlMap.isEmpty()) {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
}
else {
else {
// 这里对bean的配置进行解析, 然后调用父类的registerHandler()方法进行解析
// 这里对 bean 的配置进行解析,然后调用父类的 registerHandler()方法 进行解析
for (Map.Entry< String , Object > entry : urlMap.entrySet()) {
for (Map.Entry< String , Object > entry : urlMap.entrySet()) {
String url = entry.getKey();
String url = entry.getKey();
Object handler = entry.getValue();
Object handler = entry.getValue();
// 如果url没有斜线, 就在前面加上斜线
// 如果 url 没有斜线,就在前面加上斜线
if (!url.startsWith("/")) {
if (!url.startsWith("/")) {
url = "/" + url;
url = "/" + url;
}
}
@ -535,12 +534,12 @@ public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping {
}
}
}
}
```
```
这个SimpleUrlHandlerMapping注册过程的完成, 很大一部分需要它的基类来配合, 这个基类就是AbstractUrlHandlerMapping。在AbstractUrlHandlerMapping的处理过程中, 如果使用Bean的名称作为映射, 那么直接从容器中获取这个HTTP映射对应的Bean, 然后还要对不同的URL配置进行解析处理, 比如在HTTP请求中配置成“/”和通配符“/*” 的URL, 以及正常的URL请求, 完成这个解析处理过程以后, 会
这个 SimpleUrlHandlerMapping 注册过程的完成,很大一部分需要它的基类来配合,这个基类就是 AbstractUrlHandlerMapping。在 AbstractUrlHandlerMapping 的处理过程中,如果使用 Bean 的名称作为映射,那么直接从容器中获取这个 HTTP映射 对应的 Bean, 然后还要对不同的 URL配置 进行解析处理,比如在 HTTP请求 中配置成 “/” 和 通配符“/*” 的 URL, 以及正常的 URL请求, 完成这个解析处理过程以后, 会把 URL 和 handler 作为键值对放到一个 handlerMap 中去。
把URL和handler作为键值对放到一个handlerMap中去。
```java
```java
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
/**
/**
* 为给定的URL路径注册指定的handler处理程序
* 为给定的 URL路径 注册指定的 handler处理程序
*/
*/
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
Assert.notNull(urlPaths, "URL path array must not be null");
@ -550,14 +549,14 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
/**
/**
* 为给定的URL路径注册指定的handler处理程序
* 为给定的 URL路径 注册指定的 handler处理程序
*/
*/
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
Object resolvedHandler = handler;
// 如果使用bean名称进行映射, 就直接从IoC容器中获取该bean名称对应的handler
// 如果使用 bean名称 进行映射,就直接从 IoC容器 中获取该 bean名称 对应的 handler
if (!this.lazyInitHandlers & & handler instanceof String) {
if (!this.lazyInitHandlers & & handler instanceof String) {
String handlerName = (String) handler;
String handlerName = (String) handler;
if (getApplicationContext().isSingleton(handlerName)) {
if (getApplicationContext().isSingleton(handlerName)) {
@ -574,21 +573,21 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
}
}
else {
else {
// 处理URL是"/"的映射,把这个"/"映射的controller设置到rootHandler中
// 处理 URL 是 "/" 的映射,把这个 "/" 映射的 controller 设置到 rootHandler 中
if (urlPath.equals("/")) {
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
logger.info("Root mapping to " + getHandlerDescription(handler));
}
}
setRootHandler(resolvedHandler);
setRootHandler(resolvedHandler);
}
}
// 处理URL是"/"的映射,把这个"/"映射的controller设置到defaultHandler中
// 处理 URL 是 "/" 的映射,把这个 "/" 映射的 controller 设置到 defaultHandler 中
else if (urlPath.equals("/*")) {
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
logger.info("Default mapping to " + getHandlerDescription(handler));
}
}
setDefaultHandler(resolvedHandler);
setDefaultHandler(resolvedHandler);
}
}
// 处理正常的URL映射, 此handlerMap的key和value分别代表URL和映射的Controller
// 处理正常的 URL映射, 此 handlerMap 的 key 和 value 分别代表 URL 和 映射的Controller
else {
else {
this.handlerMap.put(urlPath, resolvedHandler);
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
if (logger.isInfoEnabled()) {
@ -599,7 +598,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
/**
/**
* 为此handler映射设置根handler, 即要为根路径( "/") 注册的handler
* 为此 handler映射 设置 根handler, 即要为根路径( "/")注册的 handler
* < p > Default is {@code null}, indicating no root handler.
* < p > Default is {@code null}, indicating no root handler.
*/
*/
public void setRootHandler(Object rootHandler) {
public void setRootHandler(Object rootHandler) {
@ -611,7 +610,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
/**
/**
* 设置此handler映射的默认handler。如果未找到特定映射, 则将返回此handler
* 设置 此handler映射 的默认 handler。如果未找到特定映射, 则将返回 此handler
*/
*/
public void setDefaultHandler(Object defaultHandler) {
public void setDefaultHandler(Object defaultHandler) {
this.defaultHandler = defaultHandler;
this.defaultHandler = defaultHandler;
@ -622,50 +621,50 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
}
}
}
}
```
```
这里的handlerMap是一个HashMap, 其中保存了URL请求和Controller的映射关系, 这个handlerMap是在AbstractUrlHandlerMapping中定义的( Map< String , object > handlerMap = new LinkedHashMap< String , object > () ) , 这个配置好URL请求和handler映射数据的handlerMap, 为Spring MVC响应HTTP请求准备好了基本的映射数据, 根据这个handlerMap以及设置于其中的映射数据, 可以方便地由
这里的 handlerMap 是一个 HashMap, 其中保存了 “URL请求” --> “Controller对象” 的映射关系,这个 handlerMap 是在 AbstractUrlHandlerMapping 中定义的( Map< String , object > handlerMap = new LinkedHashMap< String , object > () ),这个配置好 URL请求 和 handler映射数据 的 handlerMap, 为 SpringMVC 响应 HTTP请求 准备好了基本的映射数据,根据这个 handlerMap 以及设置于其中的映射数据,可以方便地由 URL请求 得到它所对应的 handler。有了这些准备工作, SpringMVC 就可以等待 HTTP请求 的到来了。
URL请求得到它所对应的handler。有了这些准备工作, Spring MVC就可以等待HTTP请求的到来了。
### 4.2 使用HandlerMapping完成请求的映射处理
### 4.2 使用HandlerMapping完成请求的映射处理
继续通过SimpleUrlHandlerMapping的实现来分析HandlerMapping的接口方法getHandler(), 该方法会根据初始化时得到的映射关系来生成DispatcherServlet需要的HandlerExecutionChain, 也就是说, 这个getHandler()方法是实际使用HandlerMapping完成请求的映射处理的地方。在前面的HandlerExecutionChain的执行过程中, 首先在AbstractHandlerMapping中启动getHandler的调用。
继续通过 SimpleUrlHandlerMapping的实现 来分析 HandlerMapping 的 接口方法getHandler(),该方法会根据初始化时得到的映射关系来生成 DispatcherServlet 需要的 HandlerExecutionChain, 也就是说, 这个 getHandler()方法 是实际使用 HandlerMapping 完成请求的映射处理的地方。在前面的 HandlerExecutionChain 的执行过程中,首先在 AbstractHandlerMapping 中启动 getHandler() 的调用。
```java
```java
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
/**
/**
* 查找给定请求的handler, 如果找不到特定的handler, 则返回到defaultHandler
* 查找给定请求的 handler, 如果找不到特定的 handler, 则返回到 defaultHandler
*/
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 模板方法模式
// 这里用到了模板方法模式, getHandler() 是一个模板方法, 定义了流程, getHandlerInternal() 则是
// 一个抽象方法,交由子类实现
Object handler = getHandlerInternal(request);
Object handler = getHandlerInternal(request);
// 如果找不到特定的handler, 则取defaultHandler
// 如果找不到特定的 handler, 则取 defaultHandler
if (handler == null) {
if (handler == null) {
handler = getDefaultHandler();
handler = getDefaultHandler();
}
}
// defaultHandler也没有则返回null
// defaultHandler 也没有则返回 null
if (handler == null) {
if (handler == null) {
return null;
return null;
}
}
// 如果该handler是String类型的, 说明它是一个beann ame
// 如果该 handler 是 String类型的, 说明它是一个 beanN ame
// 根据该beanname从IoC容器中获取真正的 handler对象
// 根据该 beanName 从 IoC容器 中获取真正的 handler对象
if (handler instanceof String) {
if (handler instanceof String) {
String handlerName = (String) handler;
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
handler = getApplicationContext().getBean(handlerName);
}
}
// 这里把handler添加到到HandlerExecutionChain中
// 这里把 handler 添加到到 HandlerExecutionChain 中
return getHandlerExecutionChain(handler, request);
return getHandlerExecutionChain(handler, request);
}
}
}
}
```
```
取得handler的具体过程在getHandlerInternal()方法中实现, 这个方法接受HTTP请求作为参数, 它的实现在AbstractHandlerMapping的子类AbstractUrlHandlerMapping中, 这个实现过程包括从HTTP请求中得到URL, 并根据URL到urlMapping中获得handler。
取得 handler 的具体过程在 getHandlerInternal()方法 中实现,这个方法接受 HTTP请求 作为参数,它的实现在 AbstractHandlerMapping 的子类 AbstractUrlHandlerMapping 中,这个实现过程包括从 HTTP请求 中得到 URL, 并根据 URL 到 urlMapping 中获得 handler。
```java
```java
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
/**
/**
* 查找给定请求的URL路径 对应的handler
* 查找 给定请求的URL 对应的 handler
*/
*/
@Override
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 从request中获取请求的URL路径
// 从 request 中获取请求的 URL路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 将得到的URL路径与handler进行匹配, 得到对应的handler, 如果没有对应的handler
// 将得到的 URL路径 与 handler 进行匹配,得到对应的 handler, 如果没有对应的 handler
// 则返回null, 这样默认的handler会被使用
// 则返回 null, 这样 默认的handler 会被使用
Object handler = lookupHandler(lookupPath, request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
if (handler == null) {
// We need to care for the default handler directly, since we need to
// We need to care for the default handler directly, since we need to
@ -674,7 +673,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
if ("/".equals(lookupPath)) {
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
rawHandler = getRootHandler();
}
}
// 使用默认的handler
// 使用 默认的handler
if (rawHandler == null) {
if (rawHandler == null) {
rawHandler = getDefaultHandler();
rawHandler = getDefaultHandler();
}
}
@ -698,7 +697,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
}
}
/**
/**
* 查找给定URL路径的handler实例
* 查找给定 URL路径 的 handler实例
*/
*/
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 直接匹配
// 直接匹配
@ -758,28 +757,28 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
}
}
}
}
```
```
经过这一系列对HTTP请求进行解析和匹配handler的过程, 得到了与请求对应的handler处理器。在返回的handler中, 已经完成了在HandlerExecutionChain中进行封装的工作, 为handler对HTTP请求的响应做好了准备。
经过这一系列对 HTTP请求 进行解析和匹配 handler 的过程,得到了与请求对应的 handler处理器。在返回的 handler 中,已经完成了在 HandlerExecutionChain 中进行封装的工作,为 handler 对 HTTP请求 的响应做好了准备。
### 4.3 DispatcherServlet对HTTP请求的分发处理
### 4.3 DispatcherServlet对HTTP请求的分发处理
DispatcherServlet是Spring MVC框架中非常重要的一个类, 不但建立了自己持有的IoC容器, 还肩负着请求分发处理的重任, 对HTTP请求的处理是在doService()方法中完成的。DispatcherServlet是HttpServlet的子类 , 与其他HttpServlet一样, 可以通过doService()来响应HTTP的请求。然而, 依照Spring MVC的使用, 业务逻辑的调用入口是在handler的handler()方法中实现的, 这是连接Spring MVC和应用业务逻辑实现的地方。
DispatcherServlet 是 SpringMVC框架 中非常重要的一个类,不但建立了自己持有的 IoC容器, 还肩负着请求分发处理的重任, 对 HTTP请求 的处理是在 doService()方法 中完成的。DispatcherServlet 是 HttpServlet 的子类 ,与其他 HttpServlet 一样,可以通过 doService() 来响应 HTTP的请求。然而, 依照 SpringMVC 的使用,业务逻辑的调用入口是在 handler 的 handler()方法 中实现的,这是连接 SpringMVC 和应用业务逻辑实现的地方。
```java
```java
public class DispatcherServlet extends FrameworkServlet {
public class DispatcherServlet extends FrameworkServlet {
/** 此servlet使用的HandlerMappings 列表 */
/** 此 DispatcherServlet 使用的 HandlerMapping对象 列表 */
private List< HandlerMapping > handlerMappings;
private List< HandlerMapping > handlerMappings;
/** 此servlet使用的HandlerAdapter列表 */
/** 此 Di spatcherS ervlet 使用的 HandlerAdapter对象 列表 */
private List< HandlerAdapter > handlerAdapters;
private List< HandlerAdapter > handlerAdapters;
/**
/**
* 公开DispatcherServlet特定的请求属性, 并将其委托给doDispatch()方法进行实际的分发
* 公开 DispatcherServlet 特定的请求属性,并将其委托给 doDispatch()方法 进行实际的分发
*/
*/
@Override
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response)
protected void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception {
throws Exception {
if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
// 得到请求的URI
// 得到 请求的URI
String requestUri = urlPathHelper.getRequestUri(request);
String requestUri = urlPathHelper.getRequestUri(request);
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()
? " resumed" : "";
? " resumed" : "";
@ -836,8 +835,8 @@ public class DispatcherServlet extends FrameworkServlet {
/**
/**
* 中央控制器,控制请求的转发
* 中央控制器,控制请求的转发
* 对请求的处理实际上是由doDispatch()来完成的, 它是DispatcherServlet完成HTTP请求分发处理的主要方法,
* 对请求的处理实际上是由 doDispatch() 来完成的,它是 DispatcherServlet 完成 HTTP请求 分发处理的主要方法,
* 包括准备ModelAndView, 调用getHandler()方法来响应HTTP请求, 然后通过执行Handler的处理来获取请求的
* 包括准备 ModelAndView, 调用 getHandler()方法 来响应 HTTP请求, 然后通过执行 Handler的处理 来获取请求的
* 处理结果,最后把结果返回出去
* 处理结果,最后把结果返回出去
*/
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
@ -849,7 +848,7 @@ public class DispatcherServlet extends FrameworkServlet {
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
// 为视图准备好一个ModelAndView, 这个ModelAndView持有handler处理请求的结果
// 为视图准备好一个 ModelAndView, 这个 ModelAndView 持有 handler处理请求的结果
ModelAndView mv = null;
ModelAndView mv = null;
Exception dispatchException = null;
Exception dispatchException = null;
@ -858,20 +857,20 @@ public class DispatcherServlet extends FrameworkServlet {
processedRequest = checkMultipart(request);
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
multipartRequestParsed = processedRequest != request;
// 2.取得处理当前请求的controller, 这里也称为 hanlder处理器, 这里并不是
// 2.取得处理当前请求的 Controller对象, 这里也称为 hanlder处理器, 这里并不是
// 直接返回controller, 而是返回的HandlerExecutionChain请求处理器链对象,
// 直接返回 controller对象 ,而是返回的 HandlerExecutionChain请求处理器链对象,
// 该对象封装了handler和interceptors
// 该对象封装了 handler 和 interceptors
mappedHandler = getHandler(processedRequest, false);
mappedHandler = getHandler(processedRequest, false);
// 如果handler为空,则返回404
// 如果 handler 为空,则返回 404
if (mappedHandler == null || mappedHandler.getHandler() == null) {
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
noHandlerFound(processedRequest, response);
return;
return;
}
}
// 3. 获取处理request的处理器适配器handler adapter
// 3. 获取处理 request 的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 获取请求方式, 如: GET, POST, PUT
// 获取 请求方式, 如: GET, POST, PUT
String method = request.getMethod();
String method = request.getMethod();
boolean isGet = "GET".equals(method);
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
if (isGet || "HEAD".equals(method)) {
@ -939,7 +938,7 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
/**
/**
* 返回此请求的HandlerExecutionChain, 按顺序尝试所有的HandlerMapping
* 返回此请求的 HandlerExecutionChain, 按顺序尝试所有的 HandlerMapping
*/
*/
@Deprecated
@Deprecated
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache)
@ -948,17 +947,17 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
/**
/**
* 返回此请求的HandlerExecutionChain
* 返回此请求的 HandlerExecutionChain
*/
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request)
protected HandlerExecutionChain getHandler(HttpServletRequest request)
throws Exception {
throws Exception {
// 遍历 此servlet使用的HandlerMapping列表
// 遍历 此servlet 使用的 HandlerMapping列表
for (HandlerMapping hm : this.handlerMappings) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler map [" + hm
logger.trace("Testing handler map [" + hm
+ "] in DispatcherServlet with name '" + getServletName() + "'");
+ "] in DispatcherServlet with name '" + getServletName() + "'");
}
}
// 查找给定请求的handler
// 查找给定请求的 handler
HandlerExecutionChain handler = hm.getHandler(request);
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
if (handler != null) {
return handler;
return handler;
@ -968,10 +967,10 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
/**
/**
* 返回此处理程序对象handler的HandlerAdapter
* 返回 此处理程序对象handler 的 HandlerAdapter
*/
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
// 对所有持有的HandlerAdapter进行匹配
// 对所有持有的 HandlerAdapter 进行匹配
for (HandlerAdapter ha : this.handlerAdapters) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
logger.trace("Testing handler adapter [" + ha + "]");
@ -985,11 +984,11 @@ public class DispatcherServlet extends FrameworkServlet {
}
}
}
}
```
```
通过判断, 可以知道这个handler是不是Controller接口的实现, 比如可以通过具体HandlerAdapter的实现来了解这个适配过程。以SimpleControllerHandlerAdapter的实现为例来了解这个判断是怎样起作用的。
通过判断,可以知道这个 handler 是不是 Controller接口 的实现,比如可以通过具体 HandlerAdapter 的实现来了解这个适配过程。以 SimpleControllerHandlerAdapter的实现 为例来了解这个判断是怎样起作用的。
```java
```java
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
// 判断要执行的handler是不是Controller类型的
// 判断要执行的 handler 是不是 Controller类型的
public boolean supports(Object handler) {
public boolean supports(Object handler) {
return (handler instanceof Controller);
return (handler instanceof Controller);
}
}
@ -1009,8 +1008,4 @@ public class SimpleControllerHandlerAdapter implements HandlerAdapter {
}
}
```
```
经过上面一系列的处理, 得到了handler对象, 接着就可以开始调用handler对象中的HTTP响应动作了。在handler中封装了应用业务逻辑, 由这些逻辑对HTTP请求进行相应的处理, 生成需要的数据, 并把这些数据封装到ModelAndView对象中去, 这个ModelAndView的数据封装是Spring MVC框架的要求。对handler来说, 这些都是通过调用handler()方法中的handleRequest()方法来触发完成的。在得到ModelAndView对象以后, 这个ModelAndView对象会被交给MVC模式中的视图类, 由视图类对ModelAndView对象中的数据进行呈现。
经过上面一系列的处理,得到了 handler对象, 接着就可以开始调用 handler对象 中的 HTTP响应动作了。在 handler 中封装了应用业务逻辑,由这些逻辑对 HTTP请求 进行相应的处理,生成需要的数据,并把这些数据封装到 ModelAndView对象 中去,这个 ModelAndView 的数据封装是 SpringMVC框架 的要求。对 handler 来说, 这些都是通过调用 handler()方法 中的 handleRequest()方法 来触发完成的。在得到 ModelAndView对象 以后,这个 ModelAndView对象 会被交给 MVC模式 中的视图类,由视图类对 ModelAndView对象 中的数据进行呈现。