zoukankan      html  css  js  c++  java
  • Spring源码追踪4——SpringMVC View解析

    这次的议题是返回json和返回普通view经过的路线差异。

    ---------------------------------------------------------------------------------

    org.springframework.web.servlet.DispatcherServlet#doDispatch

        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 {
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
    
                    // Determine handler for the current request.
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    // Determine handler adapter for the current request.
                    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 (logger.isDebugEnabled()) {
                            logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
    
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
    
                    // Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
    
                    applyDefaultViewName(request, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                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 afterCompletion
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                }
                else {
                    // Clean up any resources used by a multipart request.
                    if (multipartRequestParsed) {
                        cleanupMultipart(processedRequest);
                    }
                }
            }
        }

    1 view的设置

    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandleMethod

        private ModelAndView invokeHandleMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
    
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
            ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
    
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
            final 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();
    
                if (logger.isDebugEnabled()) {
                    logger.debug("Found concurrent result value [" + result + "]");
                }
                requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
            }
    
            requestMappingMethod.invokeAndHandle(webRequest, mavContainer); // 请求并设置mavContainer
    
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }
    
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }

    org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#getReturnValueHandler

        private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
            for (HandlerMethodReturnValueHandler returnValueHandler : returnValueHandlers) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" +
                            returnType.getGenericParameterType() + "]");
                }
                if (returnValueHandler.supportsReturnType(returnType)) { // 遍历获取合适的returnValueHandler
                    return returnValueHandler;
                }
            }
            return null;
        }

    1.1 根据viewName来解析的Handler

    org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler#supportsReturnType

        public boolean supportsReturnType(MethodParameter returnType) {
            Class<?> paramType = returnType.getParameterType();
            return (void.class.equals(paramType) || String.class.equals(paramType));
        }

    org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler#handleReturnValue

        public void handleReturnValue(
                Object returnValue, MethodParameter returnType,
                ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
                throws Exception {
    
            if (returnValue == null) {
                return;
            }
            else if (returnValue instanceof String) {
                String viewName = (String) returnValue;
                mavContainer.setViewName(viewName);
                if (isRedirectViewName(viewName)) {
                    mavContainer.setRedirectModelScenario(true);
                }
            }
            else {
                // should not happen
                throw new UnsupportedOperationException("Unexpected return type: " +
                        returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
            }
        }

    1.2 支持ResponseBody的Handler

    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType

        public boolean supportsReturnType(MethodParameter returnType) {
            return ((AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) ||
                    (returnType.getMethodAnnotation(ResponseBody.class) != null));
        }

    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

        public void handleReturnValue(Object returnValue, MethodParameter returnType,
                ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
                throws IOException, HttpMediaTypeNotAcceptableException {
    
            mavContainer.setRequestHandled(true);
            if (returnValue != null) {
                writeWithMessageConverters(returnValue, returnType, webRequest);
            }
        }

    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

        protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
                ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
                throws IOException, HttpMediaTypeNotAcceptableException {
    
            Class<?> returnValueClass = returnValue.getClass();
            HttpServletRequest servletRequest = inputMessage.getServletRequest();
            List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
            List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);
    
            Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
            for (MediaType requestedType : requestedMediaTypes) {
                for (MediaType producibleType : producibleMediaTypes) {
                    if (requestedType.isCompatibleWith(producibleType)) {
                        compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
                    }
                }
            }
            if (compatibleMediaTypes.isEmpty()) {
                throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
            }
    
            List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
            MediaType.sortBySpecificityAndQuality(mediaTypes);
    
            MediaType selectedMediaType = null;
            for (MediaType mediaType : mediaTypes) {
                if (mediaType.isConcrete()) {
                    selectedMediaType = mediaType;
                    break;
                }
                else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
                    selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                    break;
                }
            }
    
            if (selectedMediaType != null) {
                selectedMediaType = selectedMediaType.removeQualityValue();
                for (HttpMessageConverter<?> messageConverter : this.messageConverters) { // 遍历获取合适的messageConverter(mediaType)
                    if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
                        returnValue = this.adviceChain.invoke(returnValue, returnType, selectedMediaType,
                                (Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
                        ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
                        if (logger.isDebugEnabled()) {
                            logger.debug("Written [" + returnValue + "] as "" + selectedMediaType + "" using [" +
                                    messageConverter + "]");
                        }
                        return;
                    }
                }
            }
            throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
        }

    2.设置了viewName的view解析

    org.springframework.web.servlet.DispatcherServlet#processDispatchResult

        private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    
            boolean errorView = false;
    
            if (exception != null) {
                if (exception instanceof ModelAndViewDefiningException) {
                    logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException) exception).getModelAndView();
                }
                else {
                    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()) { // 如果没有设置view则不会进入viewResolver,返回json对象就不进入viewResolver
                render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                            "': assuming HandlerAdapter completed request handling");
                }
            }
    
            if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                // Concurrent handling started during a forward
                return;
            }
    
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, null);
            }
        }

    org.springframework.web.servlet.DispatcherServlet#resolveViewName

        protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
                HttpServletRequest request) throws Exception {
    
            for (ViewResolver viewResolver : this.viewResolvers) { // 遍历获取合适的viewResolver
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    return view;
                }
            }
            return null;
        }
  • 相关阅读:
    03-JS事件循环-宏任务与微任务
    10-Promise.all和Promise.race
    nodeJS-04
    nodeJS-03
    01-npm / npm install的过程 -nodemon 自动重启
    nodeJS-02
    nodeJS-01
    01-git
    比较运算符,in,instanceof——第十二级
    TCP(Transmission Control Protocol 传输控制协议)
  • 原文地址:https://www.cnblogs.com/chanedi/p/4998621.html
Copyright © 2011-2022 走看看