zoukankan      html  css  js  c++  java
  • Spring MVC之源码速读之RequestMappingHandlerAdapter

    spring-webmvc-4.3.19.RELEASE

    下面来看DispatcherServlet中的执行:

        /**
         * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
         * for the actual dispatching.
         */
        @Override
        protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (logger.isDebugEnabled()) {
                String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
                logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                        " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
            }
    
            // Keep a snapshot of the request attributes in case of an include,
            // to be able to restore the original attributes after the include.
            Map<String, Object> attributesSnapshot = null;
            if (WebUtils.isIncludeRequest(request)) {
                attributesSnapshot = new HashMap<String, Object>();
                Enumeration<?> attrNames = request.getAttributeNames();
                while (attrNames.hasMoreElements()) {
                    String attrName = (String) attrNames.nextElement();
                    if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                        attributesSnapshot.put(attrName, request.getAttribute(attrName));
                    }
                }
            }
    
            // Make framework objects available to handlers and view objects.
            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());
    
            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);
    
            try {
                doDispatch(request, response);
            }
            finally {
                if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                    // Restore the original attribute snapshot, in case of an include.
                    if (attributesSnapshot != null) {
                        restoreAttributesAfterInclude(request, attributesSnapshot);
                    }
                }
            }
        }
    org.springframework.web.servlet.DispatcherServlet#doService
        /**
         * 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 {
                    processedRequest = checkMultipart(request);//文件上传处理解析器
                    multipartRequestParsed = (processedRequest != request);//是否文件上传请求
    
                    // Determine handler for the current request. 获取匹配的HandlerExecutionChain
                    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;
                        }
                    }//todo:确认下这个代码块是不是为了处理etag?   https://www.cnblogs.com/softidea/p/5986339.html
    //执行拦截器的applyPreHandle,如果返回false,则流程直接结束 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. 执行处理器,返回mav mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv);//如果视图为空,给予设置默认视图的名称 mappedHandler.applyPostHandle(processedRequest, response, mv); //执行处理器拦截器的applyPostHandle } 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); }
    //处理请求结果。显然,此时请求已经结束【也是@ControlAdvice生效的地方】
    //如果是逻辑视图【MVC场景有指定的模板需要渲染或页面需要跳转】,则解析名称;否则,就不解析 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 afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);//执行拦截器的方法 } } else { // Clean up any resources used by a multipart request. 文件请求资源释放 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } org.springframework.web.servlet.DispatcherServlet#doDispatch

    首先看下doDispatch()方法如何找到适合的适配器来执行方法的:

        /**
         * 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 {
            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");
        }

    org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter

    0 = {RequestMappingHandlerAdapter@11772} 
    1 = {HttpRequestHandlerAdapter@11773} 
    2 = {SimpleControllerHandlerAdapter@11774}


    【0】 RequestMappingHandlerAdapter 【org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter】: 

    /**
    * Provides a method for invoking the handler method for a given request after resolving its
    * method argument values through registered {@link HandlerMethodArgumentResolver}s.
    *
    * <p>Argument resolution often requires a {@link WebDataBinder} for data binding or for type
    * conversion. Use the {@link #setDataBinderFactory(WebDataBinderFactory)} property to supply
    * a binder factory to pass to argument resolvers.
    *
    * <p>Use {@link #setHandlerMethodArgumentResolvers} to customize the list of argument resolvers.
    *
    * @author Rossen Stoyanchev
    * @author Juergen Hoeller
    * @since 3.1
    */
    public class InvocableHandlerMethod extends HandlerMethod {
    /**
    * An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
    * with their method argument and return type signature, as defined via
    * {@code @RequestMapping}.
    *
    * <p>Support for custom argument and return value types can be added via
    * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
    * Or alternatively, to re-configure all argument and return value types,
    * use {@link #setArgumentResolvers} and {@link #setReturnValueHandlers}.
    *
    * @author Rossen Stoyanchev
    * @author Juergen Hoeller
    * @since 3.1
    * @see HandlerMethodArgumentResolver
    * @see HandlerMethodReturnValueHandler
    */
    public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
    implements BeanFactoryAware, InitializingBean {
    
    【org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports】
    /**
    * This implementation expects the handler to be an {@link HandlerMethod}.
    * @param handler the handler instance to check
    * @return whether or not this adapter can adapt the given handler
    */
    @Override
    public final boolean supports(Object handler) {
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }
    /**
    * Extends {@link InvocableHandlerMethod} with the ability to handle return
    * values through a registered {@link HandlerMethodReturnValueHandler} and
    * also supports setting the response status based on a method-level
    * {@code @ResponseStatus} annotation.
    *
    * <p>A {@code null} return value (including void) may be interpreted as the
    * end of request processing in combination with a {@code @ResponseStatus}
    * annotation, a not-modified check condition
    * (see {@link ServletWebRequest#checkNotModified(long)}), or
    * a method argument that provides access to the response stream.
    *
    * @author Rossen Stoyanchev
    * @author Juergen Hoeller
    * @since 3.1
    */
    public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
    
    private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");


    ((ApplicationContextFacade) ((ServletContextResource) resource).getServletContext()).context.getContext().getDocBase():
    docBase : C:UsersTANGCH~1AppDataLocalTemp omcat-docbase.8903617127552296966.8080
    C:UsersTANGCH~1AppDataLocalTemp omcat-docbase.8903617127552296966.8080

    /**
    * Records model and view related decisions made by
    * {@link HandlerMethodArgumentResolver}s and
    * {@link HandlerMethodReturnValueHandler}s during the course of invocation of
    * a controller method.
    *
    * <p>The {@link #setRequestHandled} flag can be used to indicate the request
    * has been handled directly and view resolution is not required.
    *
    * <p>A default {@link Model} is automatically created at instantiation.
    * An alternate model instance may be provided via {@link #setRedirectModel}
    * for use in a redirect scenario. When {@link #setRedirectModelScenario} is set
    * to {@code true} signalling a redirect scenario, the {@link #getModel()}
    * returns the redirect model instead of the default model.
    *
    * @author Rossen Stoyanchev
    * @author Juergen Hoeller
    * @since 3.1
    */
    public class ModelAndViewContainer {

     【1】 HttpRequestHandlerAdapter 【org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter】

    /**
    * Adapter to use the plain {@link org.springframework.web.HttpRequestHandler}
    * interface with the generic {@link org.springframework.web.servlet.DispatcherServlet}.
    * Supports handlers that implement the {@link LastModified} interface.
    *
    * <p>This is an SPI class, not used directly by application code.
    *
    * @author Juergen Hoeller
    * @since 2.0
    * @see org.springframework.web.servlet.DispatcherServlet
    * @see org.springframework.web.HttpRequestHandler
    * @see LastModified
    * @see SimpleControllerHandlerAdapter
    */
    public class HttpRequestHandlerAdapter implements HandlerAdapter {
    
    @Override
    public boolean supports(Object handler) {
    return (handler instanceof HttpRequestHandler);
    }

    注: 这块也有点责任链模式的意思...

    下面看下RequestMappingHandlerAdapter是怎么实现support方法的,看之前先上类图。

    实际上support方法是在AbstractHandlerMethodAdapter这个父类实现的,然后给自己留个钩子方法,让子类实现

        /**
         * This implementation expects the handler to be an {@link HandlerMethod}.
         * @param handler the handler instance to check
         * @return whether or not this adapter can adapt the given handler
         */
        @Override
        public final boolean supports(Object handler) {
            return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));//延迟做决定,由子类来决定相关的逻辑
        }
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports 
    【org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter】
        /**
         * Always return {@code true} since any method argument and return value
         * type will be processed in some way. A method argument not recognized
         * by any HandlerMethodArgumentResolver is interpreted as a request parameter
         * if it is a simple type, or as a model attribute otherwise. A return value
         * not recognized by any HandlerMethodReturnValueHandler will be interpreted
         * as a model attribute.
         */
        @Override
        protected boolean supportsInternal(HandlerMethod handlerMethod) {
            return true;
        }
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal

    这里RequestMappingHandlerAdapter的supportInternal直接是返回的true,估计后续扩展其他子类可能会复杂些,这就是设计模式的好处。

    这样就找到了合适的适配器。

    拦截器这里就不在多说,这块就是返回false就不在往下执行。下面我们重点满ha.handle()方法,是如果映射参数,找到我们的方法,封装结果的。

    类图前面已经展示了,实际上handle是在父类AbstractHandlerMethodAdapter实现的

    public final ModelAndView handle(HttpServletRequest request, 
    HttpServletResponse response,
    Object handler) throws Exception { return this.handleInternal(request, response, (HandlerMethod)handler); //子类实现这个方法 } protected abstract ModelAndView handleInternal(HttpServletRequest var1,
    HttpServletResponse var2,
    HandlerMethod var3) throws Exception;
    protected final ModelAndView handleInternal(HttpServletRequest request, 
    HttpServletResponse response,
    HandlerMethod handlerMethod) throws Exception { if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { this.checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); } else { this.checkAndPrepare(request, response, true); } //看代码应该是从session中获取一些信息,然后初始化header等信息,不知道准确不?请大家指正! //这块就是根据需要是否进行同步操作 if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized(mutex) { return this.invokeHandleMethod(request, response, handlerMethod); } } } //正式进入执行环节 return this.invokeHandleMethod(request, response, handlerMethod); }

    下面这个方法非常重要,将重点讲解:

    private ModelAndView invokeHandleMethod(HttpServletRequest request, 
    HttpServletResponse response,
    HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod); //创建@InitBinder注解的方法的工厂类,进行缓存 ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);//创建@ModelAttribute@ControllerAdvice注解方法工厂并缓存 ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); //创建结果容器并初始化一些参数, mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);//执行@ModelAttribute注解的方法,将结果放到结果容器中 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(); if (this.logger.isDebugEnabled()) { this.logger.debug("Found concurrent result value [" + result + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]); //继续执行方法 return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest); //返回值了,两种情况 }
    public final void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
            Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs); //执行方法,获取返回值
            this.setResponseStatus(webRequest);
            if (returnValue == null) {
                if (this.isRequestNotModified(webRequest) || this.hasResponseStatus() || mavContainer.isRequestHandled()) {
                    mavContainer.setRequestHandled(true);
                    return;
                }
            } else if (StringUtils.hasText(this.responseReason)) {
                mavContainer.setRequestHandled(true);
                return;
            }
    
            mavContainer.setRequestHandled(false);
    
            try { //处理返回值 ,封装结果集
                this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
            } catch (Exception var6) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
                }
    
                throw var6;
            }
        }
    public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
            Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs); //处理 参数
            if (this.logger.isTraceEnabled()) {
                StringBuilder builder = new StringBuilder("Invoking [");
                builder.append(this.getMethod().getName()).append("] method with arguments ");
                builder.append(Arrays.asList(args));
                this.logger.trace(builder.toString());
            }
    
            Object returnValue = this.invoke(args); //反射执行方法
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
            }
    
            return returnValue;
        }
    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
            MethodParameter[] parameters = this.getMethodParameters();
            Object[] args = new Object[parameters.length];
    
            for(int i = 0; i < parameters.length; ++i) { //遍历方法的所有参数
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                GenericTypeResolver.resolveParameterType(parameter, this.getBean().getClass()); //获取设置参数类型
                args[i] = this.resolveProvidedArgument(parameter, providedArgs);
                if (args[i] == null) {
                    if (this.argumentResolvers.supportsParameter(parameter)) { //这块是遍历预置的参数解析器,就是前面说的责任链模式,**composite负责查找和执行
                        try { //由找到的参数解析器,来解析参数
                            args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
                        } catch (Exception var9) {
                            if (this.logger.isTraceEnabled()) {
                                this.logger.trace(this.getArgumentResolutionErrorMessage("Error resolving argument", i), var9);
                            }
    
                            throw var9;
                        }
                    } else if (args[i] == null) {
                        String msg = this.getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
                        throw new IllegalStateException(msg);
                    }
                }
            }
    
            return args;
        }

    这块没有任何注解,参数为javaBean的解析器为例:ModelAttributeMethodProcessor

    public boolean supportsParameter(MethodParameter parameter) {
            if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
                return true;
            } else if (this.annotationNotRequired) {
                return !BeanUtils.isSimpleProperty(parameter.getParameterType());
            } else {
                return false;
            }
        }
    
        public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
            String name = ModelFactory.getNameForParameter(parameter); //如果当前参数用@ModelAttribute修饰了,返回value值或者参数类型第一个字母小写
            // 获取需要绑定的表单对象,看参数容器包含name为key的对象不,有的话就用它,没有创建个新的。 
          Object attribute = mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : this.createAttribute(name, parameter, binderFactory, request);
            WebDataBinder binder = binderFactory.createBinder(request, attribute, name);
            if (binder.getTarget() != null) {
                this.bindRequestParameters(binder, request);
                this.validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }
         //以上就是参数绑定, 这块领开一篇文章详细说
            Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
            mavContainer.removeAttributes(bindingResultModel);
            mavContainer.addAllAttributes(bindingResultModel);
            return binder.getTarget();
        }

    参数就这样遍历处理,然后就开始通过反射 invoke执行了。接下来我们看是怎么封装换回结果的

    try {
                this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
            } catch (Exception var6) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace(this.getReturnValueHandlingErrorMessage("Error handling return value", returnValue), var6);
                }
    
                throw var6;
            }

    this.returnValuehandlers. 就是那个返回结果的包装类,初始化的结果解析器就保存这里,处理思路和参数解析器一样的,

    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
            HandlerMethodReturnValueHandler handler = this.getReturnValueHandler(returnType);
            Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
            handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
        }
    
        private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
            Iterator i$ = this.returnValueHandlers.iterator();
    
            HandlerMethodReturnValueHandler returnValueHandler;
            do {
                if (!i$.hasNext()) {
                    return null;
                }
    
                returnValueHandler = (HandlerMethodReturnValueHandler)i$.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Testing if return value handler [" + returnValueHandler + "] supports [" + returnType.getGenericParameterType() + "]");
                }
            } while(!returnValueHandler.supportsReturnType(returnType));
    
            return returnValueHandler;
        }

    遍历预置的所有结果解析器,结果解析器统一实现HandlerMethodReturnValueHandler 接口,实现supportReturnType方法:

    这里我们距离用@ResponseBody注解的结果解析器RequestResponseBodyMethodProcessor 前面说了,参数和结果集他都实现了

        /**
         * Whether the given {@linkplain MethodParameter method parameter} is
         * supported by this resolver.
         * @param parameter the method parameter to check
         * @return {@code true} if this resolver supports the supplied parameter;
         * {@code false} otherwise
    org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter
         */
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return parameter.hasParameterAnnotation(RequestBody.class);
        }
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsParameter
    
    
        /**
         * Whether the given {@linkplain MethodParameter method return type} is
         * supported by this handler.
         * @param returnType the method return type to check
         * @return {@code true} if this handler supports the supplied return type;
         * {@code false} otherwise
    org.springframework.web.method.support.HandlerMethodReturnValueHandler#supportsReturnType
         */
    
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
            return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                    returnType.hasMethodAnnotation(ResponseBody.class));
        }
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType
        /**
         * Handle the given return value by adding attributes to the model and
         * setting a view or setting the
         * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
         * to indicate the response has been handled directly.
         * @param returnValue the value returned from the handler method
         * @param returnType the type of the return value. This type must have
         * previously been passed to {@link #supportsReturnType} which must
         * have returned {@code true}.
         * @param mavContainer the ModelAndViewContainer for the current request
         * @param webRequest the current request
         * @throws Exception if the return value handling results in an error
    org.springframework.web.method.support.HandlerMethodReturnValueHandler#handleReturnValue
         */
    
        @Override
        public void handleReturnValue(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);//用内置的消息转换器来转换结果集
        }
    org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#handleReturnValue

    下面来看是怎么寻找可以合适的消息转换器的

        /**
         * Writes the given return type to the given output message.
         * @param value the value to write to the output message
         * @param returnType the type of the value
         * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
         * @param outputMessage the output message to write to
         * @throws IOException thrown in case of I/O errors
         * @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated
         * by the {@code Accept} header on the request cannot be met by the message converters
         */
        @SuppressWarnings("unchecked")
        protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
                ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
                throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    
            Object outputValue;
            Class<?> valueType;
            Type declaredType;
    
            if (value instanceof CharSequence) {
                outputValue = value.toString();
                valueType = String.class;
                declaredType = String.class;
            }
            else {
                outputValue = value;
                valueType = getReturnValueType(outputValue, returnType);
                declaredType = getGenericType(returnType);
            }
    
            HttpServletRequest request = inputMessage.getServletRequest();
            List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);//获取请求的MediaType,eg:"application/json"
            List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);//寻找支持这个返回类型的转换器支持的MediaType
    
            if (outputValue != null && producibleMediaTypes.isEmpty()) {
                throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
            }
    //双循环两个list,进行匹配,把复核条件的MediaType放到compatibleMediaTypes中 //TODO有些不懂得是为啥这块要过滤一遍,  后面实现了 父类也做了判断每个字类是否支持MediaType了?? 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()) { if (outputValue != null) { throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes); } return; } 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) {

                     //遍历所有消息转换器,canWrite是接口方法,相当于前面的support等,模式都是一个。然后满足的进行write。输出结果。

    if (messageConverter instanceof GenericHttpMessageConverter) {
                        if (((GenericHttpMessageConverter) messageConverter).canWrite(
                                declaredType, valueType, selectedMediaType)) {
                            outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
                                    (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                                    inputMessage, outputMessage);
                            if (outputValue != null) {
                                addContentDispositionHeader(inputMessage, outputMessage);
                                ((GenericHttpMessageConverter) messageConverter).write(
                                        outputValue, declaredType, selectedMediaType, outputMessage);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Written [" + outputValue + "] as "" + selectedMediaType +
                                            "" using [" + messageConverter + "]");
                                }
                            }
                            return;
                        }
                    }
                    else if (messageConverter.canWrite(valueType, selectedMediaType)) {
                        outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
                                (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                                inputMessage, outputMessage);
                        if (outputValue != null) {
                            addContentDispositionHeader(inputMessage, outputMessage);
                            ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
                            if (logger.isDebugEnabled()) {
                                logger.debug("Written [" + outputValue + "] as "" + selectedMediaType +
                                        "" using [" + messageConverter + "]");
                            }
                        }
                        return;
                    }
                }
            }
    
            if (outputValue != null) {
                throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
            }
        }
    org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

    这里可能有人会问,消息转换器什么时候加载的?
    是在RequestMappingHandlerAdapter这个bean实例化的时候加载的,同时加载参数和结果解析器时候注入到解析器当中的

    public RequestMappingHandlerAdapter() { //无参构造函数中初始化
            StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
            stringHttpMessageConverter.setWriteAcceptCharset(false);
            this.messageConverters = new ArrayList();
            this.messageConverters.add(new ByteArrayHttpMessageConverter());
            this.messageConverters.add(stringHttpMessageConverter);
            this.messageConverters.add(new SourceHttpMessageConverter());
            this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
        }
        private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { //构造参数解析器时候,注入进去
            List<HandlerMethodReturnValueHandler> handlers = new ArrayList();
            handlers.add(new ModelAndViewMethodReturnValueHandler());
            handlers.add(new ModelMethodProcessor());
            handlers.add(new ViewMethodReturnValueHandler());
            handlers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager));
            handlers.add(new CallableMethodReturnValueHandler());
            handlers.add(new DeferredResultMethodReturnValueHandler());
            handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
            handlers.add(new ModelAttributeMethodProcessor(false));
            handlers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.contentNegotiationManager));
            handlers.add(new ViewNameMethodReturnValueHandler());
            handlers.add(new MapMethodProcessor());
            if (this.getCustomReturnValueHandlers() != null) {
                handlers.addAll(this.getCustomReturnValueHandlers());
            }
    
            if (!CollectionUtils.isEmpty(this.getModelAndViewResolvers())) {
                handlers.add(new ModelAndViewResolverMethodReturnValueHandler(this.getModelAndViewResolvers()));
            } else {
                handlers.add(new ModelAttributeMethodProcessor(true));
            }
    
            return handlers;
        }

    下面介绍下,@ResponseBode标签用的消息转换器是MappingJacksonHttpMessageConverter;先看下类图吧

    MappingJacksonHttpMessageConverter重写了父类的write方法:

     public boolean canWrite(Class<?> clazz, MediaType mediaType) {
             return this.objectMapper.canSerialize(clazz) && this.canWrite(mediaType); //canWrite(mediaType)是父类实现的
      }
        protected boolean canWrite(MediaType mediaType) {
            if (mediaType == null || MediaType.ALL.equals(mediaType)) {
                return true;
            }
            for (MediaType supportedMediaType : getSupportedMediaTypes()) {//获取子类解析器支持的MediaType,看下是否支持
                if (supportedMediaType.isCompatibleWith(mediaType)) {
                    return true;
                }
            }
            return false;
        }
    org.springframework.http.converter.AbstractHttpMessageConverter#canWrite(org.springframework.http.MediaType)

    write方法 父类也帮着实现了,父类具体做了如输出,拼输出流头等信息

    public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
            HttpHeaders headers = outputMessage.getHeaders();
            if (headers.getContentType() == null) {
                if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
                    contentType = this.getDefaultContentType(t);
                }
    
                if (contentType != null) {
                    headers.setContentType(contentType);
                }
            }
    
            if (headers.getContentLength() == -1L) {
                Long contentLength = this.getContentLength(t, headers.getContentType());
                if (contentLength != null) {
                    headers.setContentLength(contentLength);
                }
            }
    
            this.writeInternal(t, outputMessage); //钩子方法,让子类去实现
            outputMessage.getBody().flush();
        }
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
            JsonEncoding encoding = this.getJsonEncoding(outputMessage.getHeaders().getContentType());
            JsonGenerator jsonGenerator = this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
            if (this.objectMapper.getSerializationConfig().isEnabled(Feature.INDENT_OUTPUT)) {
                jsonGenerator.useDefaultPrettyPrinter();
            }
            //这块就是默认用Jackson进行翻译结果集了
            try {
                if (this.prefixJson) {
                    jsonGenerator.writeRaw("{} && ");
                }
    
                this.objectMapper.writeValue(jsonGenerator, object);
            } catch (JsonProcessingException var6) {
                throw new HttpMessageNotWritableException("Could not write JSON: " + var6.getMessage(), var6);
            }
        }

    因为用@ResponseBody不需要返回视图,所以视图那块就返回Null,不需要渲染视图了

    https://www.cnblogs.com/haoerlv/p/8692988.html

    https://www.cnblogs.com/softidea/p/10120976.html

  • 相关阅读:
    xen虚拟机管理命令
    ipmi
    http://classworlds.codehaus.org/apiusage.html
    maven编译问题之 -The POM for XXX is invalid, transitive dependencies (if any) will not be available
    SSM项目web.xml等配置文件中如何查找类的全路径名?
    shiro安全框架学习-1
    ht-8 对arrayList中的自定义对象排序( Collections.sort(List<T> list, Comparator<? super T> c))
    ht-7 treeSet特性
    ht-6 hashSet特性
    ht-5 treemap特性
  • 原文地址:https://www.cnblogs.com/softidea/p/10210119.html
Copyright © 2011-2022 走看看