摘要:本文分析了Spring MVC的工作流程,包括请求处理的各个阶段和核心对象的协作机制。
环境
Windows 10 企业版 LTSC 21H2 Java 1.8 Tomcat 8.5.50 Maven 3.6.3 Spring 5.3.31
1 基本流程 Spring MVC的工作流程是围绕DispatcherServlet前端控制器展开的,由它统一处理所有请求。
核心流程:
说明:
发送请求。服务器接受用户请求,DispatcherServlet捕获请求。
获取处理器执行链。根据配置匹配路径,通过HandlerMapping处理器映射器获取Handler处理器和InterceptorList拦截器列表,封装为HandlerExecutionChain处理器执行链。
返回处理器执行链。返回HandlerExecutionChain处理器执行链。
获取处理器适配器。根据HandlerExecutionChain处理器执行链中的Handler处理器,匹配HandlerAdapter处理器适配器。
返回处理器适配器。返回HandlerAdapter处理器适配器。
执行业务方法。使用HandlerAdapter处理器适配器执行Handler处理器对应的业务方法,根据配置将结果封装为ModelAndView模型视图。
返回业务结果。返回ModelAndView模型视图。
处理视图。判断是否需要解析视图:如果不用解析视图,则直接返回视图;如果需要解析视图,则匹配ViewResolver视图解析器解析视图。
返回视图。使用View视图填充Model模型数据,处理响应。
响应请求。将响应返回给用户。
详细流程:
2 源码分析 2.1 请求接收 根据web.xml配置文件中的配置,使用DispatcherServlet匹配/请求,所有请求都会经过DispatcherServlet处理。
2.2 准备处理请求 DispatcherServlet继承自FrameworkServlet,FrameworkServlet间接继承自HttpServlet,请求会调用service()方法。
DispatcherServlet没有实现service()方法,所以调用FrameworkServlet的service()方法:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 protected void service (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (httpMethod == HttpMethod.PATCH || httpMethod == null ) { processRequest(request, response); } else { super .service(request, response); } }
调用HttpServlet的service()方法,根据请求类型调用方法:
java 1 2 3 4 5 protected void service (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doXxx(req, resp); }
调用FrameworkServlet的doXxx()方法,准备处理请求:
java 1 2 3 4 5 protected final void doXxx (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
2.3 开始处理请求 调用FrameworkServlet的processRequest()方法,开始处理请求:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 protected final void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor ()); initContextHolders(request, localeContext, requestAttributes); doService(request, response); }
调用DispatcherServlet的doService()方法,执行处理请求前的设置:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 protected void doService (HttpServletRequest request, HttpServletResponse response) throws Exception { request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this .localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this .themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); if (this .flashMapManager != null ) { FlashMap inputFlashMap = this .flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null ) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap ()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this .flashMapManager); } RequestPath previousRequestPath = null ; if (this .parseRequestPath) { previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE); ServletRequestPathUtils.parseAndCache(request); } doDispatch(request, response); }
调用DispatcherServlet的doDispatch()方法,继续处理请求:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = checkMultipart(request); HandlerExecutionChain mappedHandler = getHandler(processedRequest); boolean multipartRequestParsed = (processedRequest != request); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest (request, response).checkNotModified(lastModified) && isGet) { return ; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); }
2.4 获取处理器执行链 2.4.1 匹配处理器映射器 调用DispatcherServlet的getHandler()方法,获取处理器执行链:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 protected HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception { if (this .handlerMappings != null ) { for (HandlerMapping mapping : this .handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null ) { return handler; } } } return null ; }
调用AbstractHandlerMapping的getHandler()方法,获取处理器执行链:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public final HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null ) { handler = getDefaultHandler(); } if (handler == null ) { return null ; } if (handler instanceof String) { String handlerName = (String) handler; handler = obtainApplicationContext().getBean(handlerName); } if (!ServletRequestPathUtils.hasCachedPath(request)) { initLookupPath(request); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) { CorsConfiguration config = getCorsConfiguration(handler, request); if (getCorsConfigurationSource() != null ) { CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request); config = (globalConfig != null ? globalConfig.combine(config) : config); } if (config != null ) { config.validateAllowCredentials(); } executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
HandlerMapping用于根据请求获取处理器,有多种实现类:
SimpleUrlHandlerMapping:基于URL配置映射,需要显示配置映射,支持集中配置URL映射,支持通配符,支持批量配置。
RequestMappingHandlerMapping:基于@RequestMapping注解配置映射,最常用的映射器。
RouterFunctionMapping:基于函数式编程配置映射,支持根据请求路径动态配置映射。
BeanNameUrlHandlerMapping:基于对象名称配置映射,默认自带映射。
也支持通过实现HandlerMapping接口的方式自定义映射器。
2.4.2 获取处理器 调用AbstractHandlerMethodMapping的getHandlerInternal()方法,获取处理器:
java 1 2 3 4 5 6 7 8 9 protected HandlerMethod getHandlerInternal (HttpServletRequest request) throws Exception { String lookupPath = initLookupPath(request); HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null ); }
调用AbstractHandlerMethodMapping的lookupHandlerMethod()方法,根据请求路径获取处理器:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 protected HandlerMethod lookupHandlerMethod (String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList <>(); List<T> directPathMatches = this .mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null ) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { addMatchingMappings(this .mappingRegistry.getRegistrations().keySet(), matches, request); } if (!matches.isEmpty()) { Match bestMatch = matches.get(0 ); if (matches.size() > 1 ) { ... } request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod()); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.getHandlerMethod(); } else { return handleNoMatch(this .mappingRegistry.getRegistrations().keySet(), lookupPath, request); } }
2.4.3 封装处理器执行链 2.4.3.1 封装普通处理器 调用AbstractHandlerMapping的getHandlerExecutionChain()方法,封装普通处理器执行链:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 protected HandlerExecutionChain getHandlerExecutionChain (Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain (handler)); for (HandlerInterceptor interceptor : this .adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
2.4.3.2 封装跨域处理器 调用AbstractHandlerMapping的getCorsHandlerExecutionChain()方法,封装跨域处理器执行链:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 protected HandlerExecutionChain getCorsHandlerExecutionChain (HttpServletRequest request, HandlerExecutionChain chain, @Nullable CorsConfiguration config) { if (CorsUtils.isPreFlightRequest(request)) { HandlerInterceptor[] interceptors = chain.getInterceptors(); return new HandlerExecutionChain (new PreFlightHandler (config), interceptors); } else { chain.addInterceptor(0 , new CorsInterceptor (config)); return chain; } }
2.5 获取处理器适配器 调用DispatcherServlet的getHandlerAdapter()方法,获取处理器适配器:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 protected HandlerAdapter getHandlerAdapter (Object handler) throws ServletException { if (this .handlerAdapters != null ) { for (HandlerAdapter adapter : this .handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException ( ... ); }
HandlerAdapter用于根据处理器执行业务逻辑,有多种实现类:
RequestMappingHandlerAdapter:支持基于@RequestMapping注解的使用方式。最常用的适配器。
HandlerFunctionAdapter:支持基于函数式编程的使用方式。
HttpRequestHandlerAdapter:支持实现HttpRequestHandler接口的使用方式。
SimpleControllerHandlerAdapter:支持实现Controller接口的使用方式,早期适配器。
SimpleServletHandlerAdapter:支持实现Servlet接口的使用方式,早期适配器。
也支持通过实现HandlerAdapter接口的方式自定义处理。
2.6 处理业务逻辑 调用AbstractHandlerMethodAdapter的handle()方法,处理业务逻辑:
java 1 2 3 4 5 public final ModelAndView handle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
调用RequestMappingHandlerAdapter的handleInternal()方法,处理业务逻辑:
java 1 2 3 4 5 6 7 protected ModelAndView handleInternal (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { checkRequest(request); return invokeHandlerMethod(request, response, handlerMethod); }
调用RequestMappingHandlerAdapter的invokeHandlerMethod()方法,调用实际处理方法:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 protected ModelAndView invokeHandlerMethod (HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest (request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); 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)); 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(); invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null ; } return getModelAndView(mavContainer, modelFactory, webRequest); }
2.7 执行业务逻辑 调用ServletInvocableHandlerMethod的invokeAndHandle()方法,执行业务逻辑:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public void invokeAndHandle (ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null ) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true ); return ; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true ); return ; } mavContainer.setRequestHandled(false ); this .returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }
2.7.1 调用目标方法 调用InvocableHandlerMethod的invokeForRequest()方法,调用目标方法:
java 1 2 3 4 5 6 7 public Object invokeForRequest (NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); return doInvoke(args); }
调用InvocableHandlerMethod的getMethodArgumentValues()方法,获取方法参数值:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object [parameters.length]; for (int i = 0 ; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this .parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null ) { continue ; } if (!this .resolvers.supportsParameter(parameter)) { throw new IllegalStateException (formatArgumentError(parameter, "No suitable resolver" )); } args[i] = this .resolvers.resolveArgument(parameter, mavContainer, request, this .dataBinderFactory); } return args; }
调用HandlerMethodArgumentResolverComposite的resolveArgument()方法,解析参数值:
java 1 2 3 4 5 6 7 public Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
2.7.1.1 获取参数解析器 调用HandlerMethodArgumentResolverComposite的getArgumentResolver()方法,获取参数解析器:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private HandlerMethodArgumentResolver getArgumentResolver (MethodParameter parameter) { HandlerMethodArgumentResolver result = this .argumentResolverCache.get(parameter); if (result == null ) { for (HandlerMethodArgumentResolver resolver : this .argumentResolvers) { if (resolver.supportsParameter(parameter)) { result = resolver; this .argumentResolverCache.put(parameter, result); break ; } } } return result; }
HandlerMethodArgumentResolver用于将请求参数转换为方法参数值,有多种实现类:
RequestParamMethodArgumentResolver:支持处理使用@RequestParam注解的简单类型的参数。
RequestParamMapMethodArgumentResolver:支持处理使用@RequestParam注解的Map类型的参数。
PathVariableMethodArgumentResolver:支持处理使用@PathVariable注解的简单类型的参数。
PathVariableMapMethodArgumentResolver:支持处理使用@PathVariable注解的Map类型的参数。
RequestHeaderMethodArgumentResolver:支持处理使用@RequestHeader注解的简单类型的参数。
RequestHeaderMapMethodArgumentResolver:支持处理使用@RequestHeader注解的Map类型的参数。
ServletModelAttributeMethodProcessor:支持处理使用@ModelAttribute注解的参数。
ServletCookieValueMethodArgumentResolver:支持处理使用@CookieValue注解的参数。
RequestResponseBodyMethodProcessor:支持处理使用@RequestBody注解的参数。
HttpEntityMethodProcessor:支持处理使用RequestEntity类型的参数。
ModelMethodProcessor:支持处理使用Model类型的参数。
MapMethodProcessor:支持处理使用Map类型的参数。
2.7.1.2 解析参数值 2.7.1.2.1 解析请求体 如果是@RequestBody注解的参数,需要使用RequestResponseBodyMethodProcessor解析参数值。
调用RequestResponseBodyMethodProcessor的resolveArgument()方法,解析请求体:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Object resolveArgument (MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); if (binderFactory != null ) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null ) { validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException (parameter, binder.getBindingResult()); } } if (mavContainer != null ) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } return adaptArgumentIfNecessary(arg, parameter); }
调用RequestResponseBodyMethodProcessor的readWithMessageConverters()方法,读取请求体参数值:
java 1 2 3 4 5 6 7 8 9 10 11 protected <T> Object readWithMessageConverters (NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest (servletRequest); Object arg = readWithMessageConverters(inputMessage, parameter, paramType); return arg; }
调用AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters()方法,读取请求体参数值:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 protected <T> Object readWithMessageConverters (HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { MediaType contentType = inputMessage.getHeaders().getContentType(); boolean noContentType = false ; if (contentType == null ) { noContentType = true ; contentType = MediaType.APPLICATION_OCTET_STREAM; } Class<?> contextClass = parameter.getContainingClass(); Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null ); if (targetClass == null ) { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = (Class<T>) resolvableType.resolve(); } HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null ); Object body = NO_VALUE; EmptyBodyCheckingHttpInputMessage message = null ; try { message = new EmptyBodyCheckingHttpInputMessage (inputMessage); for (HttpMessageConverter<?> converter : this .messageConverters) { Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass(); GenericHttpMessageConverter<?> genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null ); if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } else { body = getAdvice().handleEmptyBody(null , message, parameter, targetType, converterType); } break ; } } } catch (IOException ex) { throw new HttpMessageNotReadableException ("I/O error while reading input message" , ex, inputMessage); } finally { if (message != null && message.hasBody()) { closeStreamIfNecessary(message.getBody()); } } if (body == NO_VALUE) { if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) { return null ; } throw new HttpMediaTypeNotSupportedException (contentType, getSupportedMediaTypes(targetClass != null ? targetClass : Object.class)); } return body; }
2.7.2 处理返回值 调用HandlerMethodReturnValueHandlerComposite的handleReturnValue()方法,使用返回值处理器处理返回值:
java 1 2 3 4 5 6 7 8 9 10 11 public void handleReturnValue (@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null ) { throw new IllegalArgumentException ( ... ); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }
2.7.2.1 获取返回值处理器 调用HandlerMethodReturnValueHandlerComposite的selectHandler()方法,获取返回值处理器:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private HandlerMethodReturnValueHandler selectHandler (@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this .returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue ; } if (handler.supportsReturnType(returnType)) { return handler; } } return null ; }
HandlerMethodReturnValueHandler用于根据返回类型处理返回值,有多种实现类:
ModelAndViewMethodReturnValueHandler:支持处理使用ModelAndView类型的返回值,用于返回使用数据的视图页面。
ViewMethodReturnValueHandler:支持处理使用View类型的返回值,用于返回视图页面。
ViewNameMethodReturnValueHandler:支持处理使用String类型的返回值,用于返回视图页面。
ModelMethodProcessor:支持处理使用Model类型的返回值,用于返回模型数据。
MapMethodProcessor:支持处理使用Map类型的返回值,用于返回模型数据。
RequestResponseBodyMethodProcessor:支持处理使用@ResponseBody注解的返回值,用于返回JSON数据。
HttpEntityMethodProcessor:支持处理使用HttpEntity类型的返回值,用于返回响应实体。
AsyncTaskMethodReturnValueHandler:支持处理使用WebAsyncTask类型的返回值,用于异步处理返回值。
DeferredResultMethodReturnValueHandler:支持处理使用DeferredResult类型的返回值,用于异步处理返回值。
CallableMethodReturnValueHandler:支持处理使用Callable类型的返回值,用于异步处理返回值。
ModelAttributeMethodProcessor:支持处理使用@ModelAttribute注解的返回值,用于设置模型数据。
也支持通过实现HandlerMethodReturnValueHandler接口的方式自定义处理器。
2.7.2.2 设置响应内容 2.7.2.2.1 普通视图 如果是普通视图的返回类型,使用ViewNameMethodReturnValueHandler处理返回值。
调用ViewNameMethodReturnValueHandler的handleReturnValue()方法,处理视图:
java 1 2 3 4 5 6 7 8 9 10 11 public void handleReturnValue (@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { String viewName = returnValue.toString(); mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true ); } }
2.7.2.2.2 内容协商 如果是@ResponseBody注解的返回类型,使用RequestResponseBodyMethodProcessor处理返回值。
调用RequestResponseBodyMethodProcessor的handleReturnValue()方法,处理内容协商:
java 1 2 3 4 5 6 7 8 9 10 11 public 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); writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
调用AbstractMessageConverterMethodProcessor的writeWithMessageConverters()方法,处理内容协商,写入返回值:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 protected <T> void writeWithMessageConverters (@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { Object body; Class<?> valueType; Type targetType; if (value instanceof CharSequence) { body = value.toString(); valueType = String.class; targetType = String.class; } else { body = value; valueType = getReturnValueType(body, returnType); targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass()); } if (isResourceType(value, returnType)) { ... } MediaType selectedMediaType = null ; MediaType contentType = outputMessage.getHeaders().getContentType(); boolean isContentTypePreset = contentType != null && contentType.isConcrete(); if (isContentTypePreset) { selectedMediaType = contentType; } else { HttpServletRequest request = inputMessage.getServletRequest(); List<MediaType> acceptableTypes = getAcceptableMediaTypes(request); List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType); List<MediaType> mediaTypesToUse = new ArrayList <>(); for (MediaType requestedType : acceptableTypes) { for (MediaType producibleType : producibleTypes) { if (requestedType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType)); } } } MediaType.sortBySpecificityAndQuality(mediaTypesToUse); for (MediaType mediaType : mediaTypesToUse) { if (mediaType.isConcrete()) { selectedMediaType = mediaType; break ; } else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) { selectedMediaType = MediaType.APPLICATION_OCTET_STREAM; break ; } } } if (selectedMediaType != null ) { selectedMediaType = selectedMediaType.removeQualityValue(); for (HttpMessageConverter<?> converter : this .messageConverters) { GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null ); if (genericConverter != null ? ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter <?>>) converter.getClass(), inputMessage, outputMessage); if (body != null ) { addContentDispositionHeader(inputMessage, outputMessage); if (genericConverter != null ) { genericConverter.write(body, targetType, selectedMediaType, outputMessage); } else { ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage); } } return ; } } } if (body != null ) { Set<MediaType> producibleMediaTypes = (Set<MediaType>) inputMessage.getServletRequest().getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) { throw new HttpMessageNotWritableException ("No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'" ); } throw new HttpMediaTypeNotAcceptableException (getSupportedMediaTypes(body.getClass())); } }
HttpMessageConverter用于设置返回值和媒体类型,有多种实现类:
ByteArrayHttpMessageConverter:用于处理字节数组。
StringHttpMessageConverter:用于处理字符串。
MappingJackson2HttpMessageConverter:用于处理JSON格式的响应,需要导入JSON依赖:pom.xml 1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > <version > 2.13.5</version > </dependency >
MappingJackson2XmlHttpMessageConverter:用于处理XML格式的响应,需要导入XML依赖。pom.xml 1 2 3 4 5 6 <dependency > <groupId > com.fasterxml.jackson.dataformat</groupId > <artifactId > jackson-dataformat-xml</artifactId > <version > 2.13.5</version > </dependency >
2.8 处理模型视图 调用RequestMappingHandlerAdapter的getModelAndView()方法,处理模型视图:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private ModelAndView getModelAndView (ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null ; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView (mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null ) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav; }
2.9 处理视图 2.9.1 准备视图 调用DispatcherServlet的processDispatchResult()方法,处理视图:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void processDispatchResult (HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { if (mv != null && !mv.wasCleared()) { render(mv, request, response); } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return ; } if (mappedHandler != null ) { mappedHandler.triggerAfterCompletion(request, response, null ); } }
调用DispatcherServlet的render()方法,渲染视图:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 protected void render (ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { Locale locale = (this .localeResolver != null ? this .localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null ) { view = resolveViewName(viewName, mv.getModelInternal(), locale, request); } else { view = mv.getView(); } if (mv.getStatus() != null ) { request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus()); response.setStatus(mv.getStatus().value()); } view.render(mv.getModelInternal(), request, response); }
2.9.2 获取视图 2.9.2.1 通过名称获取视图 调用DispatcherServlet的resolveViewName()方法,通过名称获取视图:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 protected View resolveViewName (String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { if (this .viewResolvers != null ) { for (ViewResolver viewResolver : this .viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null ) { return view; } } } return null ; }
ViewResolver用于将视图名称解析为视图对象,有多种实现类:
InternalResourceViewResolver:支持解析JSP页面。最常见的解析器。
BeanNameViewResolver:支持将逻辑视图名解析为Bean对象。
XmlViewResolver:支持解析XML文件。
ResourceBundleViewResolver:支持解析属性文件。
也支持通过实现ViewResolver接口的方式自定义处理。
2.9.2.2 通过对象获取视图 调用ModelAndView的getView()方法,通过对象获取视图:
java 1 2 3 4 public View getView () { return (this .view instanceof View ? (View) this .view : null ); }
2.9.3 渲染视图 调用AbstractView的render()方法,渲染视图:
java 1 2 3 4 5 6 7 8 9 public void render (@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
条