SprngMVC源码学习

 

 

运行helloWorld示例进入调试界面。 

 

 DispatcherServlet:前端控制器

DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 945    
DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 876    
DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 931    
DispatcherServlet(FrameworkServlet).doGet(HttpServletRequest, HttpServletResponse) line: 822    
DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 624    
DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 807    
DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 731    

由上进入源码查看

DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 807
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  ...
service();
}

  

HttpServletBean 的实现
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {}

 

 

 接下来重点关注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.
                //1、根据当前请求地址找到哪个处理器来处理请求
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                     //2、如果找不到报错
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                //2\为当前请求确定适配器
                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()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                try {
                    // Actually invoke the handler.
                    //真正执行方法
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    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
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
四步:
1)、所有请求进来都经过DispatcherServlet的900:doDispatch()方法(包含了处理请求以及响应的所有流程)
2)、916;getHandler(processedRequest);根据当前请求获取到能处理这个请求的Controller对象
3)、923:找到能执行这个Controller对象里面每一个方法的适配器
4)、945:ha.handle适配器调用目标方法(利用反射调用方法)
5)、959:转发到页面(处理响应结果)processDispatchResult
 
 
1、根据当前请求地址找到哪个处理器来处理请求
                mappedHandler = getHandler(processedRequest);

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

  

 

SpringfMVC启动的时候扫描所有的注解,将每一个类的每一个方法能处理什么请求都已经保存在handlerMapping中了;DefaultAnnotationHandlerMapping;
2、为当前请求确定适配器
 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
找到能调用这个类里面每个方法的适配器;适配器利用反射调用方法;
 
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");
	}

  

我们都使用注解模式的所以适配器使用第三个;

 

3、SpringMVC中DispatcherServlet的几个重要属性,以及赋值
SpringMVC九大组件;
 
/** MultipartResolver used by this servlet 文件上传解析器*/
    private MultipartResolver multipartResolver;

    /** LocaleResolver used by this servlet 国际化解析器*/
    private LocaleResolver localeResolver;

    /** ThemeResolver used by this servlet 主题解析器*/
    private ThemeResolver themeResolver;

    /** List of HandlerMappings used by this servlet 保存了请求与类的映射关系(哪个请求用哪个类来处理)*/
    private List<HandlerMapping> handlerMappings;

    /** List of HandlerAdapters used by this servlet适配器;用来执行控制器(处理器)目标方法的*/
    private List<HandlerAdapter> handlerAdapters;

    /** List of HandlerExceptionResolvers used by this servlet 异常解析器*/
    private List<HandlerExceptionResolver> handlerExceptionResolvers;

    /** RequestToViewNameTranslator used by this servlet 转化器*/
    private RequestToViewNameTranslator viewNameTranslator;

    /** FlashMapManager used by this servletFlashMap 管理器 */
    private FlashMapManager flashMapManager;

    /** List of ViewResolvers used by this servlet视图解析器 */
    private List<ViewResolver> viewResolvers;

 

文件上传组件默认没值;
默认赋值;
    protected void initStrategies(ApplicationContext context) {
         //默认从ioc容器中获取id为multipartResolver的组件,如果没有获取到就赋值为null
        initMultipartResolver(context);
         //按照id获取localeResolver;如果没有;
        initLocaleResolver(context);
        initThemeResolver(context);
        initHandlerMappings(context);
        initHandlerAdapters(context);
        initHandlerExceptionResolvers(context);
        initRequestToViewNameTranslator(context);
        initViewResolvers(context);
        initFlashMapManager(context);
    }
 
//1、有些组件是这么》?先获取用户配置的,如果没有可以使用默认的(MultipartResolver )
//2、有些组件是拿id获取的;有些是拿类型获取的,
//3、给SpringMVC中配置九大之一的某个组件;如果是拿id'获取的?id不要乱写,用指定id;
//如果是用类型获取,id可以不用写;
     
 
 
在于DispatcherServlet.class同目录下有一个properties文件,这里封装了所有组件默认的类型;
 
4、目标方法的运行
 
AnnotationMethodHandlerAdapter----》handle()
@Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        Class<?> clazz = ClassUtils.getUserClass(handler);
        Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
        if (annotatedWithSessionAttributes == null) {
            annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
            this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
        }

        if (annotatedWithSessionAttributes) {
            // Always prevent caching in case of session attribute management.
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
            // Prepare cached set of session attributes names.
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }

        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandlerMethod(request, response, handler);
                }
            }
        }
         //执行处理器(控制器Controller)的目标方法
        return invokeHandlerMethod(request, response, handler);
    }

  

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
          //获取方法解析器
        ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
          //根据当前请求路径,匹配每个方法的requestMapping值;并解析方法的详细信息
        Method handlerMethod = methodResolver.resolveHandlerMethod(request);
          //获取方法的执行器
        ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
          //包装request和response;
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
          //创建了一个隐含模型
        ExtendedModelMap implicitModel = new BindingAwareModelMap();
          //真正执行目标方法;    handlerMethod.invoke(handler,args)
        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
        ModelAndView mav =
                methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
        methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
        return mav;
    }
invokeHandlerMethod
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

        Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
        try {
            boolean debug = logger.isDebugEnabled();
            for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
                Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
                if (attrValue != null) {
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }

              //找到标注了ModelAttribute注解的所有方法,并执行
            for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
                Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
               //解析处理器的参数;确定当前方法要执行时要使用的所有参数;
                Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
                if (debug) {
                    logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
                }
               //找到getBook方法的ModelAttribute注解的value值;
                String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
                if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
                    continue;
                }
                ReflectionUtils.makeAccessible(attributeMethodToInvoke);
               //执行方法,ModelAttribute标注的所有方法提前执行
                Object attrValue = attributeMethodToInvoke.invoke(handler, args);
                if ("".equals(attrName)) {
                    Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
                    attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
                }
                if (!implicitModel.containsAttribute(attrName)) {
                    //将ModelAttribute标注的提前运行的方法的返回值放入隐含模型;
                    implicitModel.addAttribute(attrName, attrValue);
                }
            }

               //确定目标方法每一个参数的值;
            Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
            if (debug) {
                logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
            }
            ReflectionUtils.makeAccessible(handlerMethodToInvoke);
             //处理器目标方法执行,利用反射执行
            return handlerMethodToInvoke.invoke(handler, args);
        }
        catch (IllegalStateException ex) {
            // Internal assertion failed (e.g. invalid signature):
            // throw exception with full handler method context...
            throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
        }
        catch (InvocationTargetException ex) {
            // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
            ReflectionUtils.rethrowException(ex.getTargetException());
            return null;
        }
    }
HandlerMethodInvoker-->resolveHandlerArguments(确定目标方法使用的每一个参数值)
//确定参数值
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

        Class<?>[] paramTypes = handlerMethod.getParameterTypes();
        Object[] args = new Object[paramTypes.length];

        for (int i = 0; i < args.length; i++) {
            MethodParameter methodParam = new MethodParameter(handlerMethod, i);
            methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
            GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
            String paramName = null;
            String headerName = null;
            boolean requestBodyFound = false;
            String cookieName = null;
            String pathVarName = null;
            String attrName = null;
            boolean required = false;
            String defaultValue = null;
            boolean validate = false;
            Object[] validationHints = null;
            int annotationsFound = 0;
            Annotation[] paramAnns = methodParam.getParameterAnnotations();
               //解析参数的所有注解,把注解的信息保存起来
            for (Annotation paramAnn : paramAnns) {
                if (RequestParam.class.isInstance(paramAnn)) {
                    RequestParam requestParam = (RequestParam) paramAnn;
                    paramName = requestParam.value();
                    required = requestParam.required();
                    defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
                    annotationsFound++;
                }
                else if (RequestHeader.class.isInstance(paramAnn)) {
                    RequestHeader requestHeader = (RequestHeader) paramAnn;
                    headerName = requestHeader.value();
                    required = requestHeader.required();
                    defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
                    annotationsFound++;
                }
                else if (RequestBody.class.isInstance(paramAnn)) {
                    requestBodyFound = true;
                    annotationsFound++;
                }
                else if (CookieValue.class.isInstance(paramAnn)) {
                    CookieValue cookieValue = (CookieValue) paramAnn;
                    cookieName = cookieValue.value();
                    required = cookieValue.required();
                    defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
                    annotationsFound++;
                }
                else if (PathVariable.class.isInstance(paramAnn)) {
                    PathVariable pathVar = (PathVariable) paramAnn;
                    pathVarName = pathVar.value();
                    annotationsFound++;
                }
                else if (ModelAttribute.class.isInstance(paramAnn)) {
                    ModelAttribute attr = (ModelAttribute) paramAnn;
                    attrName = attr.value();
                    annotationsFound++;
                }
                else if (Value.class.isInstance(paramAnn)) {
                    defaultValue = ((Value) paramAnn).value();
                }
                else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
                    validate = true;
                    Object value = AnnotationUtils.getValue(paramAnn);
                    validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
                }
            }

             //以上注解不能标注多个
            if (annotationsFound > 1) {
                throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
                        "do not specify more than one such annotation on the same parameter: " + handlerMethod);
            }

            //当前参数没有找到注解
            if (annotationsFound == 0) {
               //解析普通参数(原生API);
                Object argValue = resolveCommonArgument(methodParam, webRequest);
                if (argValue != WebArgumentResolver.UNRESOLVED) {
                    args[i] = argValue;
                }
                else if (defaultValue != null) {
                    args[i] = resolveDefaultValue(defaultValue);
                }
                else {
          
                    Class<?> paramType = methodParam.getParameterType();
                    //判断是否Model和Map旗下的,将隐含模型交给这个map类型的参数
                    if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
                        if (!paramType.isAssignableFrom(implicitModel.getClass())) {
                            throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
                                    "Model or Map but is not assignable from the actual model. You may need to switch " +
                                    "newer MVC infrastructure classes to use this argument.");
                        }
                        args[i] = implicitModel;//存到map中
                    }
                    else if (SessionStatus.class.isAssignableFrom(paramType)) {
                        args[i] = this.sessionStatus;
                    }
                    else if (HttpEntity.class.isAssignableFrom(paramType)) {
                        args[i] = resolveHttpEntityRequest(methodParam, webRequest);
                    }
                    else if (Errors.class.isAssignableFrom(paramType)) {
                        throw new IllegalStateException("Errors/BindingResult argument declared " +
                                "without preceding model attribute. Check your handler method signature!");
                    }

                    //确定当前参数是否简单的基本类型参数;String,Integer ...
                    else if (BeanUtils.isSimpleProperty(paramType)) {
                        paramName = "";
                    }
                    //赋值为attrName="";
                    else {
                        attrName = "";
                    }
                }
            }



            //其他情况,有注解的情况,下边的某个if可能是成功的就会进行;
               
            if (paramName != null) {
                args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (headerName != null) {
                args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (requestBodyFound) {
                args[i] = resolveRequestBody(methodParam, webRequest, handler);
            }
            else if (cookieName != null) {
                args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
            }
            else if (pathVarName != null) {
                args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
            }



             //自定义类型对象的封装以及取值
            else if (attrName != null) {
                WebDataBinder binder =
                        resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);//后面重点介绍
                boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
                if (binder.getTarget() != null) {
                    doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
                }
                args[i] = binder.getTarget();
                if (assignBindingResult) {
                    args[i + 1] = binder.getBindingResult();
                    i++;
                }
                implicitModel.putAll(binder.getBindingResult().getModel());
            }
        }

        return args;
    }

resolveCommonArgument(解析普通参数)----resolveStandardArgument
确定参数是否可以传入的原生ServletAPI
@Override
        protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

            if (ServletRequest.class.isAssignableFrom(parameterType) ||
                    MultipartRequest.class.isAssignableFrom(parameterType)) {
                Object nativeRequest = webRequest.getNativeRequest(parameterType);
                if (nativeRequest == null) {
                    throw new IllegalStateException(
                            "Current request is not of type [" + parameterType.getName() + "]: " + request);
                }
                return nativeRequest;
            }
            else if (ServletResponse.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                Object nativeResponse = webRequest.getNativeResponse(parameterType);
                if (nativeResponse == null) {
                    throw new IllegalStateException(
                            "Current response is not of type [" + parameterType.getName() + "]: " + response);
                }
                return nativeResponse;
            }
            else if (HttpSession.class.isAssignableFrom(parameterType)) {
                return request.getSession();
            }
            else if (Principal.class.isAssignableFrom(parameterType)) {
                return request.getUserPrincipal();
            }
            else if (Locale.class.equals(parameterType)) {
                return RequestContextUtils.getLocale(request);
            }
            else if (InputStream.class.isAssignableFrom(parameterType)) {
                return request.getInputStream();
            }
            else if (Reader.class.isAssignableFrom(parameterType)) {
                return request.getReader();
            }
            else if (OutputStream.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getOutputStream();
            }
            else if (Writer.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getWriter();
            }
            return super.resolveStandardArgument(parameterType, webRequest);
        }

 

结论一:
提前运行的ModelAttribute方法的参数和目标方法的参数写法规则是一模一样的;
提前运行了ModelAttribute方法,隐含模型中会有两种东西?
1)、ModelAttribute方法Map作为参数时,给里面put的数据
2)、ModelAttribute方法返回值也放入map。
3)、都是给隐含模型中放置值
 
流程:
1)、获取所有参数类型,挨个确定每个参数对应值
2)、确定当前参数是否有注解;
          有:保存注解的详细信息;
          没有:往下走
3)、注解大于1抛异常(注解不合法),
4)、注解=0(没有注解),if -- else if
          1)确定这个参数是否原生API;是则返回,
          2)是否有默认值@Value("");没有
          3)其他情况
               1)、是否Model或者Map旗下的,是则将隐含模型赋值过来
               2)、
5)、注解正好的情况(注解ok)
          1)、其他注解
          2)、ModelAttribute注解;
                    将ModelAttribute注解的value值赋值给attrName
 
6)、确定自定义类型对象;attrName肯定不是null
       attrName的值:
          1)、参数有ModelAttribute注解attrName就是注解标注的值
          2)、参数没有ModelAttribute注解,attrName就是"";
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
            ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {

        // Bind request parameter onto object...
        String name = attrName;
        if ("".equals(name)) {
            name = Conventions.getVariableNameForParameter(methodParam);
        }
        Class<?> paramType = methodParam.getParameterType();

        //
        Object bindObject;
         //1、判断隐含模型中是否有这个key,有则从隐含模型中获取到这个值赋值給bindObject;
        if (implicitModel.containsKey(name)) {
            bindObject = implicitModel.get(name);
        }
          //2、如果隐含模型中没有看是否是SessionAttributes标注的属性,如果是从Session中获取这个key的值,赋值给bindObject
        else if (this.methodResolver.isSessionAttribute(name, paramType)) {
            bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
               //如果Session中没有查到这个值。抛异常;
            if (bindObject == null) {  
                raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
            }
        }
         //3、隐含模型中也没有这个key,SessionAttributes也没说它有。
        else {
            //  利用反射创建出一个对象
            bindObject = BeanUtils.instantiateClass(paramType);
        }
        

          //把bindObject传入,返回一个WebDataBinder(将请求传入的参数绑定到刚才创建的对象中);
        WebDataBinder binder = createBinder(webRequest, bindObject, name);
        initBinder(handler, name, binder, webRequest);
        return binder;
    }
执行目标方法并返回;
 
 
1)、确定自定义类型参数的值流程;
     1、确定Book对象的attrName;  获取标注了ModelAttribute注解的value值;如果没有就是"";(给Book对象确定一个key)
     2、一但key是"";把Book的类型首字符小写作为key
     3、查这个key的值:
          1)、判断隐含模型中是否存在这个key;如果有则返回,没有继续
          2)、看是否是SessionAttributes标注的属性;是则查询(查不到抛异常)
          3)、都不是,则利用反射创建对象;
     4、将请求带来的每一个参数封装进这个对象中;
【7、SpringMVC如何解析方法返回值(视图)】
逻辑视图(方法返回值)转为物理视图(真实页面地址)的过程;
1)、任意方法的任意返回值,最终都会被包装成一个ModelAndView对象;返回出去;既包含了视图信息又包含了模型数据;
          1)、方法执行完成以后,根据方法的返回值包装ModelAndView对象;
               方法的返回值就是页面地址。隐含模型中的所有数据就是要给页面携带的数据;
 AnnotationMethodHandlerAdapter----》handle()-----》invokeHandlerMethod()-----》 resolveModelAttribute()
 
//真正执行目标方法;    handlerMethod.invoke(handler,args)
        Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
        ModelAndView mav =
                methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
//各种数据类型最终都会转换成ModelAndView 类型
@SuppressWarnings("unchecked")
        public ModelAndView getModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue,
                ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception {

            ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class);
            if (responseStatusAnn != null) {
                HttpStatus responseStatus = responseStatusAnn.value();
                String reason = responseStatusAnn.reason();
                if (!StringUtils.hasText(reason)) {
                    webRequest.getResponse().setStatus(responseStatus.value());
                }
                else {
                    webRequest.getResponse().sendError(responseStatus.value(), reason);
                }

                // to be picked up by the RedirectView
                webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus);

                responseArgumentUsed = true;
            }

            // Invoke custom resolvers if present...
            if (customModelAndViewResolvers != null) {
                for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) {
                    ModelAndView mav = mavResolver.resolveModelAndView(
                            handlerMethod, handlerType, returnValue, implicitModel, webRequest);
                    if (mav != ModelAndViewResolver.UNRESOLVED) {
                        return mav;
                    }
                }
            }

            if (returnValue instanceof HttpEntity) {
                handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest);
                return null;
            }
            else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
                handleResponseBody(returnValue, webRequest);
                return null;
            }
            else if (returnValue instanceof ModelAndView) {
                ModelAndView mav = (ModelAndView) returnValue;
                mav.getModelMap().mergeAttributes(implicitModel);
                return mav;
            }
            else if (returnValue instanceof Model) {
                return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());
            }
            else if (returnValue instanceof View) {
                return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
            }
            else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
                addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
                return new ModelAndView().addAllObjects(implicitModel);
            }
            else if (returnValue instanceof Map) {
                return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map<String, ?>) returnValue);
            }
            else if (returnValue instanceof String) {
                return new ModelAndView((String) returnValue).addAllObjects(implicitModel);
            }
            else if (returnValue == null) {
                // Either returned null or was 'void' return.
                if (this.responseArgumentUsed || webRequest.isNotModified()) {
                    return null;
                }
                else {
                    // Assuming view name translation...
                    return new ModelAndView().addAllObjects(implicitModel);
                }
            }
            else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) {
                // Assume a single model attribute...
                addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
                return new ModelAndView().addAllObjects(implicitModel);
            }
            else {
                throw new IllegalArgumentException("Invalid handler method return value: " + returnValue);
            }
        }

  

2、959:处理返回值processDispatchResult;
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
          1)、视图解析器负责将返回值解析创建出视图对象
          2)、视图对象决定模型数据如何渲染(数据怎么展示);页面如何跳转;
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

        boolean errorView = false;
          
          //1、有异常处理异常
        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()) {
             //渲染流程
            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);
        }
    }
Render方法的内部
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Determine locale for request and apply it to the response.
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);

        View view;
        if (mv.isReference()) {
            // 1)We need to resolve the view name.视图解析器要根据返回值创建视图对象了
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException(
                        "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
                                getServletName() + "'");
            }
        }
        else {
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name '" + getServletName() + "'");
            }
        }

        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        try {
        //2)、视图对象进行渲染 view.render(mv.getModelInternal(), request, response); }
catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'", ex); } throw ex; } }
1)We need to resolve the view name.视图解析器要根据返回值创建视图对象了
View:这是一个接口;
ViewResolver:也是一个接口;
ViewResolver创建出View对象,View对象负责页面信息的渲染
ViewResolver:用户可以配置多个
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
            HttpServletRequest request) throws Exception {

          //多个视图解析器依次解析,如果某个解析成功就直接返回值;如果没有成功下一个解析器继续
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);//createView()在里面
            if (view != null) {
                return view;
            }
        }
        return null;
    }
viewResolver 根据视图名得到视图对象;resolveViewName细节;在InternalResourceViewResovler的父类中定义了创建视图对象这个方法
view = createView(viewName, locale);
@Override
    protected View createView(String viewName, Locale locale) throws Exception {
        // If this resolver is not supposed to handle the given view,
        // return null to pass on to the next resolver in the chain.
        if (!canHandle(viewName, locale)) {
            return null;
        }

        // Check for special "redirect:" prefix.如果是redirect:开始的、创建一个有重定向功能的视图对象;
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
            return applyLifecycleMethods(viewName, view);
        }
        // Check for special "forward:" prefix.如果是以forward:前缀开始,创建一个具有转发功能的视图对象;
        if (viewName.startsWith(FORWARD_URL_PREFIX)) {
            String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
            return new InternalResourceView(forwardUrl);
        }
        // Else fall back to superclass implementation: calling loadView.否则创建一个默认的View对象
          //InternalResourceView;默认的是有国际化功能的;
        return super.createView(viewName, locale);
    }
2)、视图对象进行渲染
视图对象进行渲染:DispatcherServlet---1225
@Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isTraceEnabled()) {
            logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
                " and static attributes " + this.staticAttributes);
        }

        Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);

        prepareResponse(request, response);

          //渲染模型数据;Merged:合并
  renderMergedOutputModel(mergedModel, request, response); }
视图对象如何渲染;
 @Override
    protected void renderMergedOutputModel(
            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

        // Determine which request handle to expose to the RequestDispatcher.
        HttpServletRequest requestToExpose = getRequestToExpose(request);

        // Expose the model object as request attributes.将模型中的数据暴露到request域中;底层也是把隐含模型这个map中所有的key遍历都放在request域中
        exposeModelAsRequestAttributes(model, requestToExpose);

        // Expose helpers as request attributes, if any.
        exposeHelpers(requestToExpose);

        // Determine the path for the request dispatcher.拿到转发的地址
        String dispatcherPath = prepareForRendering(requestToExpose, response);

        // Obtain a RequestDispatcher for the target resource (typically a JSP).
        RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
        if (rd == null) {
            throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
                    "]: Check that the corresponding file exists within your web application archive!");
        }

        // If already included or response already committed, perform include, else forward.
        if (useInclude(requestToExpose, response)) {
            response.setContentType(getContentType());
            if (logger.isDebugEnabled()) {
                logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
            }
            rd.include(requestToExpose, response);
        }

        else {
            // Note: The forwarded resource is supposed to determine the content type itself.
            if (logger.isDebugEnabled()) {
                logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
            }
               //转发到页面
            rd.forward(requestToExpose, response);
        }
    }
1、视图解析器负责根据返回值作为页面地址得到视图对象
2、视图对象调用渲染方法;
3、视图对象渲染(页面跳转逻辑模型数据放在请求域中
InternalResourceView:转发到页面
RedirectView:重定向到页面
JSTLView:快速国际化;只要导入了jstl的jar包,以前默认创建的InternalResouceView都会被使用jstlView替代;
     国际化的新步骤:
          1)、写好国际化资源文件
          2)、在SpringMVC配置文件中配置管理国际化资源文件的消息管理器组件
<!-- 注册一个国际化资源管理器;id必须是messageSource -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"></property>
    </bean>
   3)、去页面 使用fmt:message标签取值即可
 
 
 

 

 
posted @ 2017-08-03 12:39  lamsey16  阅读(193)  评论(0编辑  收藏  举报