对于Spring中的DispatcherServlet是什么?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍springmvc中dispatcherservlet的作用,并为您提供关于1.Sp
对于Spring 中的 Dispatcher Servlet 是什么?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍springmvc中dispatcherservlet的作用,并为您提供关于1.SpringMVC 设计理念与 DispatcherServlet、DispatcherServlet & SpringMVC 启动过程、Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?、http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception的有用信息。
本文目录一览:- Spring 中的 Dispatcher Servlet 是什么?(springmvc中dispatcherservlet的作用)
- 1.SpringMVC 设计理念与 DispatcherServlet
- DispatcherServlet & SpringMVC 启动过程
- Dubbox 的 DispatcherServlet 和 spring-mvc 的 DispatcherServlet,两者 url-pattern 抢占要怎么解决?
- http-500:Servlet.init() for servlet SpringDispatcherServlet threw exception
Spring 中的 Dispatcher Servlet 是什么?(springmvc中dispatcherservlet的作用)
在这张图片中(我从
这里
得到的), HTTP 请求向 Dispatcher Servlet 发送了一些东西。
我的问题是 Dispatcher Servlet 做什么?
是否类似于从网页中获取信息并将其扔给控制器?
答案1
小编典典DispatcherServlet 的工作是获取传入的 URI 并找到处理程序(通常是 Controller 类上的方法)和视图(通常是
JSP)的正确组合,它们组合起来形成应该在该位置找到的页面或资源。
我可能有
- 一份文件
/WEB-INF/jsp/pages/Home.jsp
- 和一个类的 方法
@RequestMapping(value="/pages/Home.html")
private ModelMap buildHome() {
return somestuff;
}
Dispatcher servlet 是“知道”在浏览器请求页面时调用该方法并将其结果与匹配的 JSP 文件组合以生成 html 文档的位。
它如何实现这一点因配置和 Spring 版本而异。
也没有理由最终结果必须是网页。它可以做同样的事情来定位 RMI 端点、处理 SOAP 请求,以及任何可以进入 servlet 的事情。
1.SpringMVC 设计理念与 DispatcherServlet
SpringMVC 作为 Struts2 之后异军突起的一个表现层框架,正越来越流行,相信 javaee 的开发者们就算没使用过 SpringMVC,也应该对其略有耳闻。我试图通过对 SpringMVC 的设计思想和源码实现的剖析,从抽象意义上的设计层面和实现意义上的代码层面两个方面,逐一揭开 SpringMVC 神秘的面纱,本文的代码,都是基于 Spring 的 3.1.3RELEASE 版本。
任何一个框架,都有自己特定的适用领域,框架的设计和实现,必定是为了应付该领域内许多通用的,烦琐的、基础的工作而生。SpringMVC 作为一个表现层框架,也必须直面 Web 开发领域中表现层中的几大课题,并给出自己的回答:
-
URL 到框架的映射。
-
http 请求参数绑定
-
http 响应的生成和输出
这三大课题,组成一个完整的 web 请求流程,每一个部分都具有非常广阔的外延。SpringMVC 框架对这些课题的回答又是什么呢?
学习一个框架,首要的是要先领会它的设计思想。从抽象、从全局上来审视这个框架。其中最具有参考价值的,就是这个框架所定义的核心接口。核心接口定义了框架的骨架,也在最抽象的意义上表达了框架的设计思想。
下面我以一个 web 请求流程为载体,依次介绍 SpringMVC 的核心接口和类。
用户在浏览器中,输入了 http://www.xxxx.com/aaa/bbb.ccc 的地址,回车后,浏览器发起一个 http 请求。请求到达你的服务器后,首先会被 SpringMVC 注册在 web.xml 中的前端转发器 DispatcherServlet 接收,DispatcherServlet 是一个标准的 Servlet,它的作用是接受和转发 web 请求到内部框架处理单元。
下面看一下第一个出现在你面前的核心接口,它是在 org.springframework.web.servlet 包中定义的 HandlerMapping 接口:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
public interface HandlerMapping {
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
为了阅读方便,我去掉了源码中的注释,但是我强烈建议你一定要记得去阅读它,这样你才能从框架的设计者口中得到最准确的关于这个类或者接口的设计说明。类中定义的几个常量,我们先不去管它。关键在于这个接口中唯一的方法:
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
这个方法就算对于一个 java 初学者来说,也很容易理解:它只有一个类型为 HttpServletRequest 的参数,throws Exception 的声明表示它不处理任何类型的异常,HandlerExecutionChain 是它的返回类型。
回到 DispatcherServlet 的处理流程,当 DispatcherServlet 接收到 web 请求后,由标准 Servlet 类处理方法 doGet 或者 doPost,经过几次转发后,最终注册在 DispatcherServlet 类中的 HandlerMapping 实现类组成的一个 List(有点拗口)会在一个循环中被遍历。以该 web 请求的 HttpServletRequest 对象为参数,依次调用其 getHandler 方法,第一个不为 null 的调用结果,将被返回。DispatcherServlet 类中的这个遍历方法不长,贴一下,让大家有更直观的了解。
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//遍历处理器映射器
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name ''" + getServletName() + "''");
}
//获取HandlerExecutionChain(处理执行链),并返回
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
是的,第一步处理就这么简单的完成了。一个 web 请求经过处理后,会得到一个 HandlerExecutionChain 对象,这就是 SpringMVC 对 URl 映射给出的回答。需要留意的是,HandlerMapping 接口的 getHandler 方法参数是 HttpServletRequest,这意味着,HandlerMapping 的实现类可以利用 HttpServletRequest 中的 所有信息来做出这个 HandlerExecutionChain 对象的生成” 决策 “。这包括,请求头、url 路径、cookie、session、参数等等一切你从一个 web 请求中可以得到的任何东西(最常用的是 url 路径)。
SpirngMVC 的第一个扩展点,就出现在这里。我们可以编写任意的 HandlerMapping 实现类,依据任何策略来决定一个 web 请求到 HandlerExecutionChain 对象的生成。可以说,从第一个核心接口的声明开始,SpringMVC 就把自己的灵活性和野心暴露无疑:哥玩的就是”Open-Closed“。
HandlerExecutionChain 这个类,就是我们下一个要了解的核心类。从名字可以直观的看得出,这个对象是一个执行链的封装。熟悉 Struts2 的都知道,Action 对象也是被层层拦截器包装,这里可以做个类比,说明 SpringMVC 确实是吸收了 Struts2 的部分设计思想。
HandlerExecutionChain 类的代码不长,它定义在 org.springframework.web.servlet 包中,为了更直观的理解,先上代码。
package org.springframework.web.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.util.CollectionUtils;
public class HandlerExecutionChain {
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
public HandlerExecutionChain(Object handler) {
this(handler, null);
}
public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<HandlerInterceptor>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
else {
this.handler = handler;
this.interceptors = interceptors;
}
}
public Object getHandler() {
return this.handler;
}
public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList();
this.interceptorList.add(interceptor);
}
public void addInterceptors(HandlerInterceptor[] interceptors) {
if (interceptors != null) {
initInterceptorList();
this.interceptorList.addAll(Arrays.asList(interceptors));
}
}
private void initInterceptorList() {
if (this.interceptorList ==