一个请求在spring MVC 中是怎么流转的
核心入口DispatcherServlet所有Spring MVC请求的入口都是DispatcherServlet。它本质上是一个Servlet其service()方法由父类FrameworkServlet实现最终会导向其核心方法doDispatch()。这个方法就像一个指挥中心调度其他组件来完成请求处理。// FrameworkServlet.javaOverrideprotectedfinalvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{processRequest(request,response);}// ... doPost, doPut, doDelete等方法类似// processRequest方法最终会调用到DispatcherServlet的doService()方法// DispatcherServlet.javaOverrideprotectedvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{// ... 做一些准备工作和属性设置 ...doDispatch(request,response);// 核心分发逻辑} 请求全链路剖析doDispatch() 源码逐段解析下面的流程图清晰地展示了doDispatch内部的核心步骤我将配合每个步骤的源码进行深入解读。“如果返回false则中断”“如果返回true则继续”客户端发起请求DispatcherServlet接收请求checkMultipart检查是否为文件上传请求getHandler通过HandlerMapping获取处理器执行链getHandlerAdapter获取支持该处理器的适配器applyPreHandle执行拦截器的preHandle方法响应返回ha.handle适配器执行处理器方法applyPostHandle执行拦截器的postHandle方法processDispatchResult处理结果及异常render视图渲染triggerAfterCompletion执行拦截器的afterCompletion方法checkMultipart处理文件上传流程开始会检查当前请求是否是一个multipart/form-data类型的文件上传请求。如果是则通过配置的MultipartResolver将HttpServletRequest对象包装为MultipartHttpServletRequest以便后续方便地获取上传的文件。getHandler定位处理器接下来系统需要找到“谁来处理这个请求”。getHandler(request)方法会遍历注册的HandlerMapping组件找到能处理当前请求的处理器Handler并返回一个包含该处理器和其关联的HandlerInterceptor拦截器的执行链。// DispatcherServlet.javaprotectedHandlerExecutionChaingetHandler(HttpServletRequestrequest)throwsException{if(this.handlerMappings!null){// 遍历所有注册的处理器映射器for(HandlerMappingmapping:this.handlerMappings){HandlerExecutionChainhandlermapping.getHandler(request);if(handler!null){returnhandler;// 返回第一个找到的处理器执行链}}}returnnull;}最常用的HandlerMapping是RequestMappingHandlerMapping它在项目启动时会扫描所有标注了Controller和RequestMapping的类和方法将请求路径和HTTP方法与目标方法封装为HandlerMethod对象的映射关系保存起来。getHandler方法的核心逻辑就在AbstractHandlerMethodMapping.lookupHandlerMethod中它会根据请求路径在内部的mappingRegistry中进行精准匹配。getHandlerAdapter查找适配器找到处理器后DispatcherServlet需要一种统一的方式来调用它因为处理器的形式可能是多样的如实现Controller接口的类或是标注了RequestMapping的方法。getHandlerAdapter方法的作用就是遍历所有注册的HandlerAdapter找到能“支持”当前处理器的那个适配器并在后续操作中使用它。// DispatcherServlet.javaprotectedHandlerAdaptergetHandlerAdapter(Objecthandler)throwsServletException{if(this.handlerAdapters!null){// 遍历所有注册的处理器适配器for(HandlerAdapteradapter:this.handlerAdapters){if(adapter.supports(handler)){// 判断是否支持该处理器returnadapter;// 返回第一个找到的适配器}}}thrownewServletException(No adapter for handler...);}对于RequestMapping注解的方法Spring MVC会为其选择RequestMappingHandlerAdapter。这个适配器是处理现代Spring MVC控制器以Controller和RequestMapping为代表的核心。拦截器「前置处理」applyPreHandle在真正调用处理器方法之前applyPreHandle方法会按照顺序执行处理器执行链中所有拦截器的preHandle方法。如果任何一个拦截器的preHandle方法返回false整个请求链路将在此被切断后续的处理器方法和视图渲染都不会执行。ha.handle执行处理器这是核心的业务处理阶段。HandlerAdapter的handle方法会利用Java的反射机制调用真正的Controller方法。在这个过程中HandlerAdapter还会负责处理诸多繁重的工作例如参数解析将请求参数Query String、Form Data、JSON等绑定到方法参数上。返回值处理将方法返回的对象如ModelAndView、POJO、ResponseEntity等转换为统一的ModelAndView对象。// RequestMappingHandlerAdapter.java (精简逻辑)OverrideprotectedModelAndViewhandleInternal(HttpServletRequestrequest,HttpServletResponseresponse,HandlerMethodhandlerMethod)throwsException{ModelAndViewmavnull;// ...// 最终会委托给 ServletInvocableHandlerMethod 来调用 Controller 方法ServletInvocableHandlerMethodinvocableMethod...;invocableMethod.invokeAndHandle(request,response,mavContainer);// ...returngetModelAndView(...);}拦截器「后置处理」applyPostHandle在处理器方法执行完毕、但视图尚未渲染之前applyPostHandle方法会按逆序执行所有拦截器的postHandle方法。如果处理器方法执行过程中抛出了异常postHandle方法将不会被执行。processDispatchResult处理结果这个方法负责处理执行结果主要包含两个子任务异常处理如果处理器执行过程中抛出了异常它会调用配置的HandlerExceptionResolver组件来解析异常生成一个包含错误视图的ModelAndView。视图渲染调用render方法渲染最终的响应结果。// DispatcherServlet.javaprivatevoidprocessDispatchResult(HttpServletRequestrequest,HttpServletResponseresponse,NullableHandlerExecutionChainmappedHandler,NullableModelAndViewmv,NullableExceptionexception)throwsException{// 1. 处理异常if(exception!null){// 调用 HandlerExceptionResolver 来解析异常生成对应的 ModelAndViewmvprocessHandlerException(request,response,mappedHandler,exception);}// 2. 视图渲染if(mv!null!mv.wasCleared()){render(mv,request,response);}// ... 清理和后续处理}render视图渲染如果ModelAndView包含视图信息非ResponseBody该方法会执行解析视图遍历所有ViewResolver调用其resolveViewName方法将逻辑视图名如user/list解析为一个具体的View对象如InternalResourceView对应/WEB-INF/jsp/userList.jsp。渲染输出调用View对象的render方法将模型数据Model填充到视图中生成最终的HTML或其他格式内容并写入HttpServletResponse。// DispatcherServlet.javaprotectedvoidrender(ModelAndViewmv,HttpServletRequestrequest,HttpServletResponseresponse)throwsException{// 解析视图名称Viewviewnull;if(mv.isReference()){// 遍历 ViewResolver 来解析视图名称viewresolveViewName(mv.getViewName(),mv.getModelInternal(),locale,request);}// 渲染视图view.render(mv.getModelInternal(),request,response);}拦截器「完成处理」triggerAfterCompletion无论请求是正常处理完成还是中途发生了异常triggerAfterCompletion方法都会在最后被调用按逆序执行所有拦截器的afterCompletion方法用于执行清理资源等收尾工作。 总览请求流转全路径总结图ViewViewResolverHandlerExceptionResolverControllerHandlerAdapterHandlerInterceptorHandlerMappingDispatcherServlet客户端ViewViewResolverHandlerExceptionResolverControllerHandlerAdapterHandlerInterceptorHandlerMappingDispatcherServlet客户端alt[存在异常]alt[preHandle返回true][preHandle返回false]发送请求checkMultipart (文件上传检查)getHandler (定位处理器)返回 HandlerExecutionChaingetHandlerAdapter (获取适配器)applyPreHandle (前置拦截)handle (执行处理器)返回ModelAndViewapplyPostHandle (后置拦截)processDispatchResult (处理结果)processHandlerException (解析异常)返回错误 ModelAndViewresolveViewName (解析视图)返回View对象render (视图渲染)返回响应直接返回 (请求中断)triggerAfterCompletion (完成清理)