zoukankan      html  css  js  c++  java
  • 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标签取值即可
     
     
     
     
  • 相关阅读:
    codeforces 673D D. Bear and Two Paths(构造)
    codeforces 673C C. Bear and Colors(暴力)
    codeforces 673B B. Problems for Round(模拟)
    codeforces 673A A. Bear and Game(水题)
    hdu-3555 Bomb(数位dp)
    西交校赛 I. GZP and CS(数位dp)
    西交校赛 F. GZP and Poker
    删除目录下包含“2018” 关键字文件
    CSV转成Excel格式
    解决字符sqlplus 乱码
  • 原文地址:https://www.cnblogs.com/limingxian537423/p/7279021.html
Copyright © 2011-2022 走看看