SpringMVC那些事-整体概述

来源:互联网 发布:淘宝网上买狗怎么寄来 编辑:程序博客网 时间:2024/06/16 12:30
名词浅析
*DispatcherServlet:分发器,把用户请求分发给控制器中的处理器处理,并处理结果和返回响应.实际上这个分发器就是一个Servlet.
*Controller:控制器,一般使用@Controller注解把类声明称控制器,控制器中使用@RequestMapping注解的方法叫做处理器
*Handler:处理器,中处理请求的,也就是使用@RequestMapping注解的方法叫做处理器
*HandlerMapping:内含了@RequestMapping注解配置的信息和对应的处理器的关系.SpringMVC会解析当前请求,会根据URL,method,header等匹配对应的控制器
*HandlerExecutionChain:处理链,包含了拦截器链和处理器
*HandlerAdapter:为处理器构造参数(包括数据绑定和数据校验等),调用反射调用处理器,解析处理器返回的结果等
*ViewResolver:视图解析器,根据处理器返回的数据模型的viewName生成具体的视图类,例如JstlView, PdfView等

一个请求被完整处理过程是:
  1.hm根据请求request构造HandlerExecutionChain
  2.匹配合适的ha, 然后由ha构造参数调用处理器,然后解析处理器返回的结果
  3.如果处理器返回的是视图模型,渲染视图,返回客户端.


1.匹配处理链的过程
1.1相关类

DispatcherServlet
  MultipartResolver multipartResolver//上传文件解析器
  List<HandlerMapping> handlerMappings//所有配置的hm
  List<HandlerAdapter> handlerAdapters//所有配置的ha
  List<HandlerExceptionResolver> handlerExceptionResolvers//异常解析器
  List<ViewResolver> viewResolvers//所有配置的视图解析器

RequestMappingInfo @RequestMapping注解配置参数的封装
  PatternsRequestCondition patternsCondition;//value = {"path"}:路径正在匹配,路径配置可以使用{id}这样的restful风格
  RequestMethodsRequestCondition methodsCondition;//例如method = {RequestMethod.GET}
  ParamsRequestCondition paramsCondition;//例如params = {"name=weber"}
  HeadersRequestCondition headersCondition;//例如headers={"content-type=text/*"}
  ConsumesRequestCondition consumesCondition;//例如consumes = {"text/plain", "application/json"}消费者,其实就是请求需要的类型,例如发送json数据到服务器
  ProducesRequestCondition producesCondition;//例如produces = {"text/plain", "application/json"}生产者,相应的类型,例如返回json数据给客户端
  RequestConditionHolder customConditionHolder;//
 
RequestMappingHandlerMapping 生成当前请求的HandlerExecutionChain,主要使用它的父类方法,如下:

AbstractHandlerMethodMapping
  LinkedHashMap<RequestMappingInfo, HandlerMethod> handlerMethods//映射URL信息和处理器
  LinkedMultiValueMap<String, RequestMappingInfo> urlMap//保存处理器注解的URL基本信息

AbstractHandlerMapping
  Object defaultHandler;
  UrlPathHelper urlPathHelper = new UrlPathHelper();
  PathMatcher pathMatcher = new AntPathMatcher();//ant风格的URL解析
  List<Object> interceptors = new ArrayList<Object>();//
  List<HandlerInterceptor> adaptedInterceptors//
  List<MappedInterceptor> mappedInterceptors//路径和拦截器的关系封装,可以根据当前路径很快的匹配到当前处理器需要使用的拦截器
 
HandlerExecutionChain 包含了拦截器链和需要处理请求的控制器
  Object handler目标处理器
  HandlerInterceptor[] interceptors 拦截器链
HandlerExecutionChain由HandlerMapping生成,SpringMVC遍历所有的HandlerMapping,直到有其中
一个HandlerMapping能返回HandlerExecutionChain为止,也就是找到当前请求对应的处理器为止.

HandlerMethod 表示一个类函数的封装类,包括函数的Method和所属的类,和函数的参数等.例如Controller中的每一个处理器可以用它表示,请看hm中和ha具体使用
  Object bean;//控制器
  BeanFactory beanFactory;//XMLApplicationContext
  Method method;//处理器
  bridgedMethod;//桥接处理器
  MethodParameter[] parameters;//处理器参数

拦截器相关
MappedInterceptor//封装了路径和拦截器的关系
  String[] includePatterns;
  String[] excludePatterns;
  HandlerInterceptor interceptor;//ConversionServiceExposingInterceptor
  PathMatcher pathMatcher;
   

1.2函数处理过程
根据hm中的request(url,method,header等)根据urlMap和handlerMethods查找合适的HandlerMethod(处理器)
然后找到HandlerMethod之后,生成一个HandlerExecutionChain,遍历拦截器,把处理器需要使用的拦截器放入.
1.dispatcherservlet.getHandler
  -> hm.getHandler(request)
  -> AbstractHandlerMapping.getHandler
  -> AbstractHandlerMethodMapping.getHandlerInternal/AbstractHandlerMapping.getDefaultHandler //如果找不到合适的处理器,就返回默认的处理器
  -> AbstractHandlerMethodMapping.lookupHandlerMethod//匹配合适的处理器(关键部分,使用urlMap和handlerMethods查找)
  -> AbstractHandlerMapping.getHandlerExecutionChain(handler, request)//遍历注册的拦截器,根据lookupPath和拦截器路径匹配,合适的就加进去(注意一些内置的拦截器)


2.ha的处理过程
2.1相关类


Model 数据模型

DataBinder
  Object target;//需要绑定数据的参数,例如处理器的参数
  String objectName;//参数名称
  AbstractPropertyBindingResult bindingResult//绑定结果,例如数据校验失败的信息
  BindingErrorProcessor bindingErrorProcessor//绑定异常解析器
  List<Validator> validators//数据校验器
  ConversionService conversionService//

WebDataBinder 从request请求参数中数据绑定到Java对象(数据类型转换和格式化,数据校验)
  从原始的Request中取出参数,然后进行数据绑定(原始的Request中的请求参数都是String类型)

MethodParameter 表示类方法参数的类, 例如处理器的参数
 
HandlerMethodArgumentResolver
HandlerMethodReturnValueHandler
ModelAttributeMethodProcessor 解析使用@ModelAttribute注解的参数,和使用@ModelAttribute注解 处理器返回值

ServletModelAttributeMethodProcessor应用WebDataBinder进行数据绑定

ModelAndViewContainer 记录HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler和生成的model和view
  Object view;
  ModelMap defaultModel = new BindingAwareModelMap();
  ModelMap redirectModel;

HandlerMethodArgumentResolverComposite
  List<HandlerMethodArgumentResolver> argumentResolvers
  Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache
 
InvocableHandlerMethod 可以调用HandlerMethod的类,用来调用处理器
  WebDataBinderFactory dataBinderFactory
  HandlerMethodArgumentResolverComposite argumentResolvers
  ParameterNameDiscoverer parameterNameDiscoverer

HandlerMethodReturnValueHandler
HandlerMethodReturnValueHandlerComposite 使用returnValueHandlers解析处理器返回的结果
  List<HandlerMethodReturnValueHandler> returnValueHandlers
 
ServletInvocableHandlerMethod 可以处理返回结果的InvocableHandlerMethod,使用returnValueHandlers解析处理器返回的结果
  HandlerMethodReturnValueHandlerComposite returnValueHandlers

RequestMappingHandlerAdapter
   
2.2handler的执行过程
为处理器构造参数(设计数据绑定和数据校验,例如使用了@RequestBody把json数据转换成Java数据模型),
然后通过反射调用处理器,最后解析处理器返回的结果(例如使用了@ResponseBody返回json数据),最后返回一个数据模型(ModelAndView)
视图渲染在下一个过程
  -> AbstractHandlerMethodAdapter.handle
  -> RequestMappingHandlerAdapter.handleInternal
  -> RequestMappingHandlerAdapter.invokeHandleMethod//构建WebDataBinderFactory,ModelFactory,ModelAndViewContainer
  -> ServletInvocableHandlerMethod.invokeAndHandle
  -> InvocableHandlerMethod.invokeForRequest
  -> InvocableHandlerMethod.getMethodArgumentValues//构造处理器的参数
  -> InvocableHandlerMethod.getMethodParameters
  -> HandlerMethodArgumentResolverComposite.resolveArgument
  -> HandlerMethodArgumentResolverComposite.getArgumentResolver//遍历argumentResolvers,选择合适的解析类
  -> ModelAttributeMethodProcessor.resolveArgument//数据类型转换,格式化,数据绑定,数据校验
  -> InvocableHandlerMethod.invoke//最终调用处理器的地方
  -> HandlerMethodReturnValueHandlerComposite.handleReturnValue//处理返回的结果, 例如@ResponseBody返回json数据,注意返回视图的情况
  -> RequestMappingHandlerAdapter.getModelAndView//获取视图模型

 

3.视图解析
3.1相关类
VIew 视图抽象类,表示jsp, pdf, xml等视图的抽象

ModelAndView模型和视图的封装

ViewResolver 视图解析器,生成具体的试图类

InternalResourceViewResolver 内置资源写解析器,可以解析JstlView

RequestDispatcher
ApplicationDispatcher

3.2
(主要包括:生成具体的视图(JSTL,PDF等),渲染视图;或者是把异常生成视图处理. 不包括@ResponseBody返回json这样的数据处理)
根据处理器的返回值使用ViewResolver构造视图,最后渲染视图
->dispatcherservlet.processDispatchResult//处理返回的视图模型,
->dispatcherservlet.render
->dispatcherservlet.resolveViewName//遍历ViewResolver,和hm一样的策略,生成具体的View,注意ViewResolver使用Order接口,也就是根据这个决定优先级
->JstlView.render//调用具体的视图类渲染视图


部分源码注释
DispatcherServlet

/** * 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 {//如果是文件上传请求,那么将会生成一个不一样的request.实际上使用的是common upload这个第三方jarprocessedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.//遍历hm数组, 找到可以url对应的处理器,然后注入拦截器,然后把它俩封装返回mappedHandler = getHandler(processedRequest);if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.//遍历ha数组获取合适的haHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//获取ha// 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;}}                //执行处理链中的拦截连的preif (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}try {// Actually invoke the handler.//ha调用处理器,1:给处理器生成参数,这个过程包括数据类型转换格式化,数据绑定和数据校验等    //2:使用1中的参数通过反射调用处理器;    //3:处理处理器返回的结果,如果是使用了@ResponseBody会把数据刷入响应流中//4:返回mv, 如果返回的不是视图, 那么mv == nullmv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}}applyDefaultViewName(request, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}//处理返回的视图,视图渲染在这里发生 当时候@ResponseBody这样的注解的时候,是不返回视图的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 afterCompletionmappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if (multipartRequestParsed) {//知道我们为什么前面需要使用一个变量来标记当前请求是上传文件了,因为文件上传可能占用不少的内存,需要释放一下cleanupMultipart(processedRequest);}}}

/** * 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 {//遍历hm数组,直到第一个hm可以根据当前request(url, method, header等,//也就是我们在控制器方法使用的@RequestMapping使用的参数)可以解析HandlerExecutionChain出来,包括了拦截器和处理器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;}

/** * 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 {//遍历ha, 直到找到第一个可以处理处理链的ha. 和找hm类似, 实际上, 在SpringMVC中很多地方都重要了这样的方法,后面会看到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");}


0 0