> 文章列表 > Spring MVC(3)-MVC执行流程分析

Spring MVC(3)-MVC执行流程分析

Spring MVC(3)-MVC执行流程分析

执行流程

  1. 用户发起请求,请求到达DispatcherServlet。
  2. DispatcherServlet#doDispatch 分发处理请求;
  3. AbstractHandlerMapping#getHandler 匹配Request处理器
  4. HandlerExecutionChain#applyPreHandle 执行HandlerInterceptor前置校验;
  5. DispatcherServlet#getHandlerAdapter 获取处理器适配器,核心逻辑,包含Method参数转换、把Method返回值转换并且写入Response;
  6. HandlerExecutionChain#applyPostHandle 执行HandlerInterceptor后置处理;
  7. DispatcherServlet#processDispatchResult 异常、HandlerInterceptor#afterCompletion处理。
  8. FrameworkServlet#publishRequestHandledEvent
    发布一个事件,表示该请求处理完毕,无论成功与否。

DispatcherServlet#doDispatch

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;/* TODO预处理:1. 获取HandlerMethod和过滤器链的包装类(url-hanlderMethod映射):HandlerExecutionChain,里面包含了handlerMethod对象2. 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式调用链:1. 前置拦截,正向遍历调用,若有返回false,则调用后置处理,返回。interceptor.preHandle(request, response, this.handler)triggerAfterCompletion(request, response, null);2. 根据HandlerAdapter获取真正的处理类,执行:((Controller) handler).handleRequest(request, response)3. 中置拦截,反向遍历调用。 interceptor.postHandle(request, response, this.handler, mv);4. 视图渲染,在视图渲染之后,会在视图渲染方法中调用后置处理。render(mv, request, response);if (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}*/// 异步管理WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {ModelAndView mv = null;Exception dispatchException = null;try {// 检查是否文件上传//检查方式:校验contentType是否已 multipart/ 开头//如果是 文件上传,request转为 StandardMultipartHttpServletRequestprocessedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// 重点:获取封装了 handlerMethod、拦截器的执行链封装 HandlerExecutionChain。// @Controller 使用 RequestMappingHandlerMapping// 包含ConversionServiceExposingInterceptor、ResourceUrlProviderExposingInterceptor拦截器// handler为HandlerMethodmappedHandler = getHandler(processedRequest);//匹配不到处理器,如果throwExceptionIfNoHandlerFound=false(默认false)返回404if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// TODO 获取跟HandlerMethod匹配的HandlerAdapter对象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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// TODO 前置过滤器,如果为false则直接返回if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// TODO 重点,调用到Controller具体方法,核心方法调用。// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);// TODO 执行中置拦截mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}// TODO 处理结果,这里执行了后置拦截。在前面的流程里捕获了业务方法执行过程中抛出的异常。//  如果上面的流程中抛出了异常,则dispatchException一定有值。processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}

AbstractHandlerMapping#getHandler

获取适配当前Request的HandlerExecutionChain
处理流程:

  1. 查询可以处理Request的handler,@Controller标注的类handler为HandlerMethod
  2. 构建HandlerExecutionChain类,包含handler、HandlerInterceptor
  3. 是否CORS请求,如果是预验证(使用OPTIONS请求并且header包含Access-Control-Request-Method)使用PreFlightHandler包装handler;如果不是预验证,增加一个CorsInterceptor拦截器。
	/DispatcherServlet#getHandler 方法*/@Nullableprotected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// handlerMappering实例if (this.handlerMappings != null) {// 在 DispatcherServlet 初始化的时候,会将handlerMappings的值,赋值到这里。for (HandlerMapping mapping : this.handlerMappings) {// 获取HandlerMethod和拦截器链的包装类//@Controller 使用 RequestMappingHandlerMappingHandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;}/AbstractHandlerMapping#getHandler 方法匹配handler并且使用HandlerExecutionChain 包装*/public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// TODO 获取 HandlerMethod// @Controller标注的类handler为HandlerMethodObject handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instanceof String) {String handlerName = (String) handler;handler = obtainApplicationContext().getBean(handlerName);}// 将 handlerMethod,包装到 HandlerExecutionChain 中。// HandlerExecutionChain除包含handlerMethod外,还装配了当前请求的HandlerInterceptorHandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);if (logger.isTraceEnabled()) {logger.trace("Mapped to " + handler);}else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {logger.debug("Mapped to " + executionChain.getHandler());}//是否CORS请求,通过header中是否有Originif (CorsUtils.isCorsRequest(request)) {CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);}return executionChain;}

DispatcherServlet#getHandlerAdapter

获取跟HandlerMethod匹配的HandlerAdapter对象。
Spring MVC装配了3个HandlerAdapter:

  1. RequestMappingHandlerAdapter:主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器
  2. HttpRequestHandlerAdapter:主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。
  3. SimpleControllerHandlerAdapter:Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController.
	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {// 根据handlerMethod对象,找到合适的HandlerAdapter对象,这里是典型的的策略模式// 遍历所有的 handlerAdapters,并调用其 supports(),如果有 adapter 支持这个 handlerMethod,就返回这个 adapter。// handlerAdapters包含:// 		RequestMappingHandlerAdapter:主要是适配注解类处理器,注解类处理器就是我们经常使用的@Controller的这类处理器//		HttpRequestHandlerAdapter:主要是适配静态资源处理器,静态资源处理器就是实现了HttpRequestHandler接口的处理器,这类处理器的作用是处理通过SpringMVC来访问的静态资源的请求。//		SimpleControllerHandlerAdapter:Controller处理适配器,适配实现了Controller接口或Controller接口子类的处理器,比如我们经常自己写的Controller来继承MultiActionController.if (this.handlerAdapters != null) {for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}}}throw new ServletException("No adapter for handler [" + handler +"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}

HandlerExecutionChain#applyPreHandle

执行HandlerInterceptor的前置校验,任何一个返回false即停止往下执行。

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {//默认有两个拦截器://ConversionServiceExposingInterceptor:// 用于向请求添加一个属性,属性名称为ConversionService.class.getName(),值是Spring MVC配置定义的一个类型转换服务。该类型转换服务会在请求处理过程中用于请求参数或者返回值的类型转换。//ResourceUrlProviderExposingInterceptor:// 用于向请求添加一个属性,属性名称为ResourceUrlProvider.class.getName(),值是Spring MVC配置定义的一个资源URL提供者对象ResourceUrlProvider。for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];// 遍历执行拦截器的前置方法,只要有一个返回了false,就返回false。// 每次执行一个前置拦截后,就将interceptorIndex+1,当有前置方法返回false时,执行triggerAfterCompletion。if (!interceptor.preHandle(request, response, this.handler)) {// 倒序执行后置拦截,起始索引是 interceptorIndex,即如果也有前置拦截执行失败了,// 那么相应的这个失败的及之后的拦截器的后置拦截就不会执行。triggerAfterCompletion(request, response, null);return false;}this.interceptorIndex = i;}}return true;}

HandlerAdapter#handle

	/调用具体的业务逻辑*/@Override@Nullablepublic final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return handleInternal(request, response, (HandlerMethod) handler);}/RequestMappingHandlerAdapter#handleInternal*/@Overrideprotected ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ModelAndView mav;//检查请求方法是否支持和session是否存在checkRequest(request);// Execute invokeHandlerMethod in synchronized block if required.// synchronizeOnSession=false(默认)if (this.synchronizeOnSession) {HttpSession session = request.getSession(false);if (session != null) {Object mutex = WebUtils.getSessionMutex(session);synchronized (mutex) {mav = invokeHandlerMethod(request, response, handlerMethod);}}else {// No HttpSession available -> no mutex necessarymav = invokeHandlerMethod(request, response, handlerMethod);}}else {// TODO Controller里面具体方法调用,重点看// No synchronization on session demanded at all...mav = invokeHandlerMethod(request, response, handlerMethod);}if (!response.containsHeader(HEADER_CACHE_CONTROL)) {if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);}else {prepareResponse(response);}}return mav;}/RequestMappingHandlerAdapter#invokeHandlerMethod把request转换成Method的参数、调用Method、Method返回结果处理*/@Nullableprotected ModelAndView invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {ServletWebRequest webRequest = new ServletWebRequest(request, response);try {// 获取数据绑定工厂  @InitBinder注解支持,没太多用WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);// Model工厂,收集了@ModelAttribute注解的方法ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);// 可调用的方法对象ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) {// 设置参数解析器invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);}if (this.returnValueHandlers != null) {// 设置返回值解析器invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);}// 设置参数绑定工厂invocableMethod.setDataBinderFactory(binderFactory);// 设置参数名称解析类invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);ModelAndViewContainer mavContainer = new ModelAndViewContainer();mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));// 调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法// 把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了modelFactory.initModel(webRequest, mavContainer, invocableMethod);mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);asyncWebRequest.setTimeout(this.asyncRequestTimeout);// 异步处理WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.setTaskExecutor(this.taskExecutor);asyncManager.setAsyncWebRequest(asyncWebRequest);asyncManager.registerCallableInterceptors(this.callableInterceptors);asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);if (asyncManager.hasConcurrentResult()) {Object result = asyncManager.getConcurrentResult();mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];asyncManager.clearConcurrentResult();LogFormatUtils.traceDebug(logger, traceOn -> {String formatted = LogFormatUtils.formatValue(result, !traceOn);return "Resume with async result [" + formatted + "]";});invocableMethod = invocableMethod.wrapConcurrentResult(result);}// TODO 重点:解析Request参数为目标方法参数、校验目标方法参数、Controller方法调用invocableMethod.invokeAndHandle(webRequest, mavContainer);if (asyncManager.isConcurrentHandlingStarted()) {return null;}return getModelAndView(mavContainer, modelFactory, webRequest);}finally {webRequest.requestCompleted();}}/ServletInvocableHandlerMethod#invokeAndHandle调用具体业务逻辑、把Method返回值写入response*/public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {// TODO 重点:具体方法调用逻辑Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);setResponseStatus(webRequest);if (returnValue == null) {if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {mavContainer.setRequestHandled(true);return;}}else if (StringUtils.hasText(getResponseStatusReason())) {mavContainer.setRequestHandled(true);return;}mavContainer.setRequestHandled(false);Assert.state(this.returnValueHandlers != null, "No return value handlers");try {// TODO 使用返回值处理器,对返回值进行处理// returnValueHandlers 使用 HandlerMethodReturnValueHandlerComposite 实例this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}catch (Exception ex) {if (logger.isTraceEnabled()) {logger.trace(formatErrorForReturnValue(returnValue), ex);}throw ex;}}/HandlerMethodReturnValueHandlerComposite#handleReturnValue查找具体的handler并且处理返回值*/@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {// TODO 查找返回值处理器,策略模式的一种运用HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);// 如果不存在返回值处理器,则跑出异常if (handler == null) {throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());}// 对返回值进行处理handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}/HandlerMethodReturnValueHandlerComposite#selectHandler*/@Nullableprivate HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {boolean isAsyncValue = isAsyncReturnValue(value, returnType);// 遍历容器中所有的返回值处理器,判断是否支持,如果有返回值处理器支持这个返回值,则返回此处理器。// 这也是策略模式的一种运用。for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {continue;}//@ResponseBody标注使用RequestResponseBodyMethodProcessorif (handler.supportsReturnType(returnType)) {return handler;}}return null;}/RequestResponseBodyMethodProcessor#handleReturnValue把Method返回值写入response*/@Overridepublic void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage = createInputMessage(webRequest);ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);// 使用消息转换器写出响应信息。// Try even with null return value. ResponseBodyAdvice could get involved.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

AbstractMessageConverterMethodArgumentResolver#validateIfApplicable

AbstractMessageConverterMethodArgumentResolver#validateIfApplicable 校验 @Validated注解标记的参数,实际由DataBinder#validate(java.lang.Object...)校验,DataBinder代理Validator列表,遍历Validator列表对参数进行校验。

	protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {Annotation[] annotations = parameter.getParameterAnnotations();for (Annotation ann : annotations) {Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});binder.validate(validationHints);break;}}}

HandlerExecutionChain#applyPostHandle

执行HandlerInterceptor后置处理。

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {// 如果存在拦截器,倒序执行中置拦截。能执行到这个方法,说明所有的前置拦截都成功执行了。for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}

DispatcherServlet#processDispatchResult

主要用来处理前面返回的结果,其中包括处理异常、渲染页面、触发 Interceptor 的 afterCompletion 方法三部分内容,处理的异常是在处理请求 doDispatch 方法的过程中产生。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,@Nullable Exception exception) throws Exception {boolean errorView = false;// 如果前面的流程中抛出了异常,在这里会进行处理。if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {// TODO 异常处理Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);errorView = (mv != null);}}// Did the handler return a view to render?//执行页面渲染操作if (mv != null && !mv.wasCleared()) {render(mv, request, response);if (errorView) {WebUtils.clearErrorRequestAttributes(request);}}else {if (logger.isTraceEnabled()) {logger.trace("No view rendering, null ModelAndView returned.");}}if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {// Concurrent handling started during a forwardreturn;}// Handler请求处理完,触发Interceptor的afterCompletionif (mappedHandler != null) {mappedHandler.triggerAfterCompletion(request, response, null);}}

FrameworkServlet#publishRequestHandledEvent

发布一个事件,表示该请求处理完毕,无论成功与否。

/* 发布一个事件,表示该请求处理完毕,无论成功与否* @param request 当前request* @param response 当前response* @param startTime 请求处理开始时间戳毫秒* @param failureCause 失败原因(抛出的异常,可能为null)*/private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,long startTime, @Nullable Throwable failureCause) {//如果允许发布事件并且关联的IoC容器不为null,那么无论我们是否成功,都发布一个事件。if (this.publishEvents && this.webApplicationContext != null) {//计算请求处理花费的时间long processingTime = System.currentTimeMillis() - startTime;//通过IoC容器发布ServletRequestHandledEvent事件,包含各种请求信息//这样我们就可以使用Spring的事件监听机制来监听这个事件进而来监听这个请求了this.webApplicationContext.publishEvent(//this:事件源,当前DispatcherServlet对象new ServletRequestHandledEvent(this,//请求路径、ip地址request.getRequestURI(), request.getRemoteAddr(),//请求方法、ServletNamerequest.getMethod(), getServletConfig().getServletName(),//SessionId、usernameWebUtils.getSessionId(request), getUsernameForRequest(request),//请求处理时间、失败原因、响应状态码processingTime, failureCause, response.getStatus()));}}

类信息

  1. HandlerMethodArgumentResolver:将方法参数解析为参数值;
  2. HandlerMethodReturnValueHandler:用于处理从Controller方法的调用返回的值;
  3. RequestResponseBodyMethodProcessor:实现HandlerMethodArgumentResolverHandlerMethodReturnValueHandler,处理@RequestBody注解