SpringMVC系列之主要组件
一、组件说明
- DispatcherServlet:前端控制器,用于请求到达前端控制器,由它调用其他组件处理用户的请求。
- HandlerMapping:处理器映射器,负责根据用户请求找到Handler(处理器),springmvc提供了不同的映射器实现方式。
- Handler:处理器,对具体的用户请求进行处理。
- HandlerAdapter:处理器适配器,通过HandlerAdapter对处理器进行执行。
- View Resolver:视图解析器,负责将处理结果生成view视图。View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
二、前端控制器
DispatcherServlet是springmvc的中央调度器,DispatcherServlet创建时会默认从DispatcherServlet.properties文件加载springmvc所用的各种组件。

二、处理器映射器
处理器映射器负责根据request请求找到对应的Handler处理器以及Interceptor拦截器,将它们封装在HandlerExecutionChain对象中返回给前端控制器。
下面是两种常用的处理器映射器:
1、BeanNameURLHandlerMapping:根据请求的url与spring容器中定义的bean的name进行匹配,从而从spring容器中找到bean实例。

2、simpleURLHandlerMapping:它可以将url和处理器bean的id进行统一映射配置。

三、处理器适配器
HandlerAdapter会根据适配器接口对Handler进行包装适配,包装后即可对处理器进行执行(使用了适配器模式)。
下面是两种常用的处理器适配器:
1、SimpleControllerHandlerAdapter:简单控制器处理器适配器,所有实现了org.springframework.web.servlet.mvc.Controller 接口的bean通过此适配器进行适配执行。

2、HttpRequestHandlerAdapter:http请求处理器适配器,所有实现了org.springframework.web.HttpRequestHandler接口的bean通过此适配器进行适配执行。

注:处理器实现HttpRequestHandler接口,实现handleRequest方法,该方法没有返回、ModelAndView,可以通过response修改定义响应内容,比如返回json数据。

四、注解处理器映射器和适配器

可以使用组件扫描,而省去在spring容器中配置每个controller类。配置如下:
<context:component-scan base-package="com.demo.ssm.controller"></context:component-scan>
1、注解处理器映射器,对类中标记的@RequestMapping的方法进行映射,根据RequestMapping定义的url匹配RequestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。
<!-- 注解映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
2、注解处理器适配器,对标记的@RequestMapping的方法进行适配。
<!-- 注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
注:还可以使用下面的配置代替上面处理器映射器和适配器的配置:
<mvc:annotation-driven></mvc:annotation-driven>
五、总结
springmvc处理流程:
1、用户发送请求到DispatchServlet前端控制器。
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
} if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
} applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
2、DispatchServlet调用HandlerMapping处理器映射器根据url查找Handler。
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} 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 handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
3、DispatchServlet调用HandlerAdapter处理器适配器对HandlerMapping找到的Handler进行包装。
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
4、执行Handler,并返回一个ModelAndView。
/**
* Determine an error ModelAndView via the registered HandlerExceptionResolvers.
* @param request current HTTP request
* @param response current HTTP response
* @param handler the executed handler, or {@code null} if none chosen at the time of the exception
* (for example, if multipart resolution failed)
* @param ex the exception that got thrown during handler execution
* @return a corresponding ModelAndView to forward to
* @throws Exception if no error ModelAndView found
*/
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
if (!exMv.hasView()) {
exMv.setViewName(getDefaultViewName(request));
}
if (logger.isDebugEnabled()) {
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
} throw ex;
}
5、DispatchServlet调用ViewResolver视图解析器进行视图解析,解析完成后返回一个View,再进行视图渲染并展示。
/**
* Render the given ModelAndView.
* <p>This is the last stage in handling a request. It may involve resolving the view by name.
* @param mv the ModelAndView to render
* @param request current HTTP servlet request
* @param response current HTTP servlet response
* @throws ServletException if view is missing or cannot be resolved
* @throws Exception if there's a problem rendering the view
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale); View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
} // Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
SpringMVC系列之主要组件的更多相关文章
- Spring Web MVC中的页面缓存支持 ——跟我学SpringMVC系列
Spring Web MVC中的页面缓存支持 ——跟我学SpringMVC系列
- React 深入系列2:组件分类
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列2:组件分类 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加 ...
- React 深入系列4:组件的生命周期
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列4:组件的生命周期 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助 ...
- SpringMVC系列之(二) springMVC和Struts异同
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring ...
- JS组件系列——Bootstrap Select2组件使用小结
前言:在介绍select组件的时候,博主之前分享过一篇JS组件系列——两种bootstrap multiselect组件大比拼,这两个组件的功能确实很强大,只可惜没有图文结合的效果(也就是将图片放入到 ...
- k8s入门系列之扩展组件(一)DNS安装篇
DNS (domain name system),提供域名解析服务,解决了难于记忆的IP地址问题,以更人性可读可记忆可标识的方式映射对应IP地址. Cluster DNS扩展插件用于支持k8s集群系统 ...
- 【SpringMVC】SpringMVC系列1之HelloWorld
SpringMVC之HelloWorld 概述 SpringMVC 是基于 MVC 设计理念的优秀Web 框架,是目前最主流的 MVC 框架之一.Spring3.0 后全面超越 Struts2,成为最 ...
- SpringMVC 系列教程1-文件上传-配置
SpringMVC默认没有配置上传解析器 使用SpringMVC来处理上传必须添加对MultipartResolver上传解析器的声明配置. 配置之后,客户端每次进行请求的时候,SpringMVC都会 ...
- SpringMVC系列(十二)自定义拦截器
Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口– preHandle():这个方法在业务处 ...
随机推荐
- 用Python中的tkinter模块作图(续)
八.显示文字 用create_text在画布上写字.这个函数只需要两个坐标(文字x和y的位置),还有一个具名参数来接受要显示的文字.例如: >>> from tkinter impo ...
- 对SingleTask和TaskAffinity的理解(转至 http://www.2cto.com/kf/201311/254450.html)
最近研究微信调起自己客户端的事情,对于SingleTask和TaskAffinity的理解又多了一些理解. 以前对于Android的四种LaunchMode有一些了解,其中比较有意思的就是Sing ...
- QIIME1 聚OTU
qiime 本身不提供聚类的算法,它只是对其他聚otu软件的封装 根据聚类软件的算法,分成了3个方向: de novo: pick_de_novo_otus.py ...
- Spring-core中的cglib小用法
对象复制听说用这个更高效 /** * 拷贝对象 * @param src 源对象 * @param dist 需要赋值的对象 */ public static void copy(Object src ...
- HTML5/CSS3实现五彩进度条应用
今天要介绍的是一款基于HTML5和CSS3的进度条应用,这款进度条是静态的,仅提供进度条的五彩外观.当然你可以在CSS中动态设置进度值来让其变得动态,一个很好的实现方式是利用jQuery动态改变CSS ...
- 无向带权图的最小生成树算法——Prim及Kruskal算法思路
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- EayRadius 于 2013-7-19 进行体验度更新,增加用户体验度
EasyRadius于2013-7-19进行更新,此次更新并没有更新通讯接口,通讯接口将统一更新,包括对其他路由的支持 下面我将主要更新的地方向大家描述一下 如果你有疑问或者建议,可以致电137799 ...
- UFLDL教程练习(exercise)答案(2)
主成分分析与白化,这部分很简单,当然,其实是用Matlab比较简单,要是自己写SVD分解算法,足够研究好几个月的了.下面是我自己实现的练习答案,不保证完全正确,不过结果和网站上面给出的基本一致. 1. ...
- String学习之-深入解析String#intern
引言 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String.这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念.常量池就类似一个JAVA系统级别提供的缓存. 8 ...
- django时区设置(timezone)
django时区设置(timezone): 默认: TIMEZONE:'America/Chicago'(以前的版本,现在的版本默认的都是UTC时间.) Chicago时间,为UTC/GMT -6 小 ...