SpringMVC-http请求处理路线

核心架构的具体流程步骤如下:

1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

 

用我的话来概括如下:

    由HandlerMapping得到HandlerExecutionChain(其包含Object handler,interceptors),handler就是Controller实例,接着由handler得到HandlerAdapter(ha),最后由ha.handle(..)得到ModelAndView。注意,在执行目标方法之前,会升序调用interceptors,之后又会倒序调用interceptors。那么,HandlerAdapter是个什么东西呢,我在DispatcherServlet.properties里可以看到默认配了3种adapter,其实还有一种adapter没加进配置文件,如果你了解springmvc的发展史和解决mvc的思路,你就会明白为什么有多种实现方式了。最初springmvc采用的是实现Controller接口的方式,javase 1.5开始,springmvc采用了更方便的注解方式来标明Controller类,这两种方式对应的adapter分别是SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,所以我们可以重点关注AnnotationMethodHandlerAdapter。


下面来好好谈谈DispatcherServlet的部分代码

    我们注意到该类中定义了一些well-known常量,呵呵,众所周知的常量

 

Java代码  

  1. public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";  
  2.   
  3. public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";  
  4.   
  5. public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";  
  6.   
  7. /** 
  8.  * Well-known name for the HandlerMapping object in the bean factory for this namespace. 
  9.  * Only used when "detectAllHandlerMappings" is turned off. 
  10.  * @see #setDetectAllHandlerMappings 
  11.  */  
  12. public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";  
  13.   
  14. public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";  
  15.   
  16. public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";  
  17.   
  18. public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";  
  19.   
  20. public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";  
  21.   
  22. public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";  
  23.   
  24. private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";  

 我们在配置文件中给相关组件bean命名时,可以保持和只写常量值一致,毕竟别人的命名是相当标准的,不过,这从逻辑上不是必须的,你甚至可以不声明bean的id,因为该类提供了如下变量

Java代码  

  1. /** Detect all HandlerMappings or just expect "handlerMapping" bean? */  
  2.     private boolean detectAllHandlerMappings = true;  
  3.   
  4.     /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */  
  5.     private boolean detectAllHandlerAdapters = true;  
  6.   
  7.     /** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */  
  8.     private boolean detectAllHandlerExceptionResolvers = true;  
  9.   
  10.     /** Detect all ViewResolvers or just expect "viewResolver" bean? */  
  11.     private boolean detectAllViewResolvers = true;  
  12.   
  13.     /** Perform cleanup of request attributes after include request? */  
  14.     private boolean cleanupAfterInclude = true;  
  15.   
  16.     /** MultipartResolver used by this servlet */  
  17.     private MultipartResolver multipartResolver;  
  18.   
  19.     /** LocaleResolver used by this servlet */  
  20.     private LocaleResolver localeResolver;  
  21.   
  22.     /** ThemeResolver used by this servlet */  
  23.     private ThemeResolver themeResolver;  
  24.   
  25.     /** List of HandlerMappings used by this servlet */  
  26.     private List<HandlerMapping> handlerMappings;  
  27.   
  28.     /** List of HandlerAdapters used by this servlet */  
  29.     private List<HandlerAdapter> handlerAdapters;  
  30.   
  31.     /** List of HandlerExceptionResolvers used by this servlet */  
  32.     private List<HandlerExceptionResolver> handlerExceptionResolvers;  
  33.   
  34.     /** RequestToViewNameTranslator used by this servlet */  
  35.     private RequestToViewNameTranslator viewNameTranslator;  
  36.   
  37.     /** FlashMapManager used by this servlet */  
  38.     private FlashMapManager flashMapManager;  
  39.   
  40.     /** List of ViewResolvers used by this servlet */  
  41.     private List<ViewResolver> viewResolvers;  

初始化方法中,执行了组件的初始化

 

Java代码  

  1. protected void initStrategies(ApplicationContext context) {  
  2.     initMultipartResolver(context);  
  3.     initLocaleResolver(context);  
  4.     initThemeResolver(context);  
  5.     initHandlerMappings(context);  
  6.     initHandlerAdapters(context);  
  7.     initHandlerExceptionResolvers(context);  
  8.     initRequestToViewNameTranslator(context);  
  9.     initViewResolvers(context);  
  10.     initFlashMapManager(context);  
  11. }  

 我们拿出initHandlerMappings(context)来瞅瞅

 

Java代码  

  1. /** 
  2.      * Initialize the HandlerMappings used by this class. 
  3.      * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, 
  4.      * we default to BeanNameUrlHandlerMapping. 
  5.      */  
  6.     private void initHandlerMappings(ApplicationContext context) {  
  7.         this.handlerMappings = null;  
  8.   
  9.         if (this.detectAllHandlerMappings) {  
  10.             // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.  
  11.             Map<String, HandlerMapping> matchingBeans =  
  12.                     BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);  
  13.             if (!matchingBeans.isEmpty()) {  
  14.                 this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());  
  15.                 // We keep HandlerMappings in sorted order.  
  16.                 OrderComparator.sort(this.handlerMappings);  
  17.             }  
  18.         }  
  19.         else {  
  20.             try {  
  21.                 HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);  
  22.                 this.handlerMappings = Collections.singletonList(hm);  
  23.             }  
  24.             catch (NoSuchBeanDefinitionException ex) {  
  25.                 // Ignore, we'll add a default HandlerMapping later.  
  26.             }  
  27.         }  
  28.   
  29.         // Ensure we have at least one HandlerMapping, by registering  
  30.         // a default HandlerMapping if no other mappings are found.  
  31.         if (this.handlerMappings == null) {  
  32.             this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);  
  33.             if (logger.isDebugEnabled()) {  
  34.                 logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");  
  35.             }  
  36.         }  
  37.     }  

 通过该方法我们可以知道,当detectAllHandlerMappings为true时,直接到mvc容器及其父容器中寻找所有类型为HandlerMapping的bean,而detectAllHandlerMappings默认恰为true,因此我们完全可以不声明bean的id。当detectAllHandlerMappings为false时(可通过在web.xml里配置servlet参数来改变默认值),则在mvc容器寻找名为"handlerMapping"的bean。如以上两种情况都没找到bean,将会实例化DispatcherServlet.properties中配置的bean。

    doService方法里有这么一段

 

Java代码  

  1. // Keep a snapshot of the request attributes in case of an include,  
  2.         // to be able to restore the original attributes after the include.  
  3.         Map<String, Object> attributesSnapshot = null;  
  4.         if (WebUtils.isIncludeRequest(request)) {  
  5.             attributesSnapshot = new HashMap<String, Object>();  
  6.             Enumeration<?> attrNames = request.getAttributeNames();  
  7.             while (attrNames.hasMoreElements()) {  
  8.                 String attrName = (String) attrNames.nextElement();  
  9.                 if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {  
  10.                     attributesSnapshot.put(attrName, request.getAttribute(attrName));  
  11.                 }  
  12.             }  
  13.         }  

 这是用于对页面有include的情况做的请求数据快照处理。

下面进入重点doDispatch方法

 

Java代码  

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.         HttpServletRequest processedRequest = request;  
  3.         HandlerExecutionChain mappedHandler = null;  
  4.         boolean multipartRequestParsed = false;  
  5.   
  6.         WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);  
  7.   
  8.         try {  
  9.             ModelAndView mv = null;  
  10.             Exception dispatchException = null;  
  11.   
  12.             try {  
  13.             // multipart包装处理,我们常用CommonsMultipartResolver  
  14.                                 processedRequest = checkMultipart(request);  
  15.                 multipartRequestParsed = processedRequest != request;  
  16.   
  17.                 // Determine handler for the current request.  
  18.                 mappedHandler = getHandler(processedRequest, false);  
  19.                 if (mappedHandler == null || mappedHandler.getHandler() == null) { // 404  
  20.                     noHandlerFound(processedRequest, response);  
  21.                     return;  
  22.                 }  
  23.   
  24.                 // Determine handler adapter for the current request.  
  25.                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  26.   
  27.                 // Process last-modified header, if supported by the handler.  // 代码省略  
  28.                   
  29.                                 // 调用目标方法前,顺序执行拦截器  
  30.                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
  31.                     return;  
  32.                 }  
  33.   
  34.                 try {  
  35.                     // Actually invoke the handler.  
  36.                     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  37.                 }  
  38.                 finally {  
  39.                     if (asyncManager.isConcurrentHandlingStarted()) {  
  40.                         return;  
  41.                     }  
  42.                 }  
  43.   
  44.                 applyDefaultViewName(request, mv);  
  45.                 // 调用目标方法后逆序执行拦截器  
  46.                                 mappedHandler.applyPostHandle(processedRequest, response, mv);  
  47.             }  
  48.             catch (Exception ex) {  
  49.                 dispatchException = ex;  
  50.             }  
  51.             processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);  
  52.         }  
  53.         catch (Exception ex) {  
  54.             triggerAfterCompletion(processedRequest, response, mappedHandler, ex);  
  55.         }  
  56.         catch (Error err) {  
  57.             triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);  
  58.         }  
  59.         finally {  
  60.             if (asyncManager.isConcurrentHandlingStarted()) {  
  61.                 // Instead of postHandle and afterCompletion  
  62.                 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
  63.                 return;  
  64.             }  
  65.             // Clean up any resources used by a multipart request.  
  66.             if (multipartRequestParsed) {  
  67.                 cleanupMultipart(processedRequest);  
  68.             }  
  69.         }  
  70.     }  

 

HandlerExecutionChain 

Java代码  

  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {  
  2.         if (getInterceptors() != null) {  
  3.             for (int i = 0; i < getInterceptors().length; i++) {  
  4.                 HandlerInterceptor interceptor = getInterceptors()[i];  
  5.                 if (!interceptor.preHandle(request, response, this.handler)) {  
  6.                     triggerAfterCompletion(request, response, null);  
  7.                     return false;  
  8.                 }  
  9.                 this.interceptorIndex = i;  
  10.             }  
  11.         }  
  12.         return true;  
  13.     }  
  14.   
  15.     /** 
  16.      * Apply postHandle methods of registered interceptors. 
  17.      */  
  18.     void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {  
  19.         if (getInterceptors() == null) {  
  20.             return;  
  21.         }  
  22.         for (int i = getInterceptors().length - 1; i >= 0; i--) {  
  23.             HandlerInterceptor interceptor = getInterceptors()[i];  
  24.             interceptor.postHandle(request, response, this.handler, mv);  
  25.         }  
  26.     }  
  27.   
  28.     /** 
  29.      * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. 
  30.      * Will just invoke afterCompletion for all interceptors whose preHandle invocation 
  31.      * has successfully completed and returned true. 
  32.      */  
  33.     void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)  
  34.             throws Exception {  
  35.   
  36.         if (getInterceptors() == null) {  
  37.             return;  
  38.         }  
  39.         for (int i = this.interceptorIndex; i >= 0; i--) {  
  40.             HandlerInterceptor interceptor = getInterceptors()[i];  
  41.             try {  
  42.                 interceptor.afterCompletion(request, response, this.handler, ex);  
  43.             }  
  44.             catch (Throwable ex2) {  
  45.                 logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);  
  46.             }  
  47.         }  
  48.     }  

 

HandlerInterceptor

Java代码  

  1. public interface HandlerInterceptor {  
  2.   
  3.     boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  4.         throws Exception;  
  5.   
  6.     void postHandle(  
  7.             HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
  8.             throws Exception;  
  9.   
  10.     void afterCompletion(  
  11.             HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
  12.             throws Exception;  
  13.   
  14. }  

 

 自定义

Java代码  

  1. public class ExceptionHandler implements HandlerExceptionResolver {  
  2.   
  3.     @Override  
  4.     public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {  
  5.         request.setAttribute("exception",ex.getMessage());  
  6.         ModelAndView mav = new ModelAndView();  
  7.         mav.setViewName("/error");  
  8.         return mav;  
  9.     }  
  10. }  

  

原文链接:[http://wely.iteye.com/blog/2296899]

时间: 2024-11-10 00:39:03

SpringMVC-http请求处理路线的相关文章

SpringMVC处理静态文件源码分析

SpringMVC处理静态资源,主要是两个标签,mvc:resources和mvc:default-servlet-handler.在详细说明他们的原理之前,需要先简单说明下SpringMVC中请求处理机制:HandlerMapping和HandlerAdapter. 1 HandlerMapping和HandlerAdapter的来由 用过python Django框架的都知道Django对于访问方式的配置就是,一个url路径和一个函数配对,你访问这个url,就会直接调用这个函数,简单明了 然

SpringMVC概览

对于任何事物的研究,总是由表及里.由浅入深地进行.在本系列的第二篇文章中,我们将通过不同的观察视角,对SpringMVC做一些概要性的分析,帮助大家了解SpringMVC的基本构成要素.SpringMVC的发展历程以及SpringMVC的设计原则.  SpringMVC的构成要素  了解一个框架的首要任务就是搞清楚这个框架的基本构成要素.当然,这里所说的构成要素实际上还可以被挖掘为两个不同的层次:  基于框架所编写的应用程序的构成要素 框架自身的运行主线以及微观构成要素 我们在这里首先来关注一下

SpringMVC前传

在我们熟知的建立在三层结构(表示层.业务逻辑层.持久层)基础之上的J2EE应用程序开发之中,表示层的解决方案最多.因为在表示层自身的知识触角很多,需要解决的问题也不少,这也就难免造成与之对应的解决方案层出不穷.  笔者在很多讨论中经常可以看到类似"某某框架已死",或者"某某框架已经足以打败所有其他的框架"的言论.事实上,每一种解决方案都有着自身独有的存在价值和历史背景.如果单单从某一个方面或者某几个方面去看一个框架,那么评论难免有失偏颇.  所以,整个系列的第一篇文

javaweb异常提示信息统一处理(使用springmvc,附源码)

版权声明:本文为博主原创文章,转载注明出处http://blog.csdn.net/u013142781 目录(?)[+] 一.前言 后台出现异常如何友好而又高效地回显到前端呢?直接将一堆的错误信息抛给用户界面,显然不合适. 先不考虑代码实现,我们希望是这样的: (1)如果是页面跳转的请求,出现异常了,我们希望跳转到一个异常显示页面,如下: 当然,这里的界面不够美观,但是理论是这样的. (2)如果是ajax请求,那么我们,希望后台将合理的错误显示返回到ajax的回调函数里面,如下: $.ajax

SpringMVC请求时如何找到正确的Controller

前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html 我们使用浏览器通过地址 http://ip:port/contextPath/path进行访问,SpringMVC是如何得知用户到底是访问哪个Controller中的方法,这期间到底发生了什么. 本文将分析SpringMVC是如何处理请求与Controll

给予Java初学者的学习路线建议

Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍.这一部分的内容,同样适用于一些希望转行到Java的同学. 在大家看之前,我要先声明两点. 1.由于我本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照

一位资深程序员大牛给予Java初学者的学习路线建议

Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍.这一部分的内容,同样适用于一些希望转行到Java的同学. 在大家看之前,我要先声明两点.1.由于我本人是Java后端开发出身,因此所推荐的学习内容是Java Web和Java后端开发的路线,非Java Web和Java后端开发的同学请适当参考其学习思想即可,切勿照搬

使用IntelliJ IDEA开发SpringMVC网站(三)数据库配置

原文:使用IntelliJ IDEA开发SpringMVC网站(三)数据库配置 摘要 讲解在IntelliJ IDEA中,如何进行Mysql数据库的配置 目录[-] 文章已针对IDEA 15做了一定的更新,部分更新较为重要,请重新阅读文章并下载最新源码. 六.数据库配置 1.创建Mysql数据库 2.IntelliJ IDEA导入数据库 3.配置数据库 更新: 转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生). 注:在阅读本文前,请先阅读: 使用IntelliJ ID

【SSH系列】深入浅出SpringMvc+入门Demo

Spring MVC框架是有一个MVC框架,通过实现Model-View-Controller模式来很好地将数据.业务与展现进行分离.从这样一个角度来说,Spring MVC和Struts.Struts2非常类似.Spring MVC的设计是围绕DispatcherServlet展开的,DispatcherServlet负责将请求派发到特定的handler.通过可配置的handler mappings.view resolution.locale以及theme resolution来处理请求并且