springmvc中形参的map/model对象是如何将它们添加的键值对放到request保存域中的

分析如何将map/model的数据放入request保存域

  • 以下源码不需要全看,主要看写了中文注释的地方即可,一步一步进去就明白了
/*首先是进入到DispatcherServlet这个中央控制器中的doDispatcher()方法里的这一步(每个请求都会经由
DispatcherServlet处理,进入到doDispatcher()方法)*/
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//=========进入ha.handle
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {

    return handleInternal(request, response, (HandlerMethod) handler);
}
//================进入handleInternal
protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    checkRequest(request);

    // 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) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No HttpSession available -> no mutex necessary
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // No synchronization on session demanded at all...
        //进入的就是这里
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }

    return mav;
}
//================进入invokeHandlerMethod(request, response, handlerMethod);
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        //这里会创建mavContainer
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();
            LogFormatUtils.traceDebug(logger, traceOn -> {
                String formatted = LogFormatUtils.formatValue(result, !traceOn);
                return "Resume with async result [" + formatted + "]";
            });
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }

        //进入的就是这里
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}
//===================进入invocableMethod.invokeAndHandle(webRequest, mavContainer);
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {

    //invokeFOrRequest,进入的就是这里
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    setResponseStatus(webRequest);

    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}
//=================进入invokeForRequest(webRequest, mavContainer, providedArgs)
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {

    //进入这里面会返回args数组,这个args数组保存的就是我们需要的每个参数解析后的值/对象
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    //!!!!执行我们的控制器方法,底层是一系列反射
    return doInvoke(args);
}
//===================进入getMethodArgumentValues(request, mavContainer, providedArgs)
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                                           Object... providedArgs) throws Exception {

    MethodParameter[] parameters = getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    }

    //args数组保存的就是每个参数的值
    Object[] args = new Object[parameters.length];
    //这个for循环一次对每个参数进行赋值,存放在args数组中
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            //进入这里!!!
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        }
        catch (Exception ex) {
            // Leave stack trace for later, exception may actually be resolved and handled...
            if (logger.isDebugEnabled()) {
                String exMsg = ex.getMessage();
                if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                    logger.debug(formatArgumentError(parameter, exMsg));
                }
            }
            throw ex;
        }
    }
    return args;
}
//===================进入args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory)
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		if (resolver == null) {
			throw new IllegalArgumentException("Unsupported parameter type [" +
					parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
		}
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}
//================分两步,先进入getArgumentResolver(parameter)找到当前参数对应的参数解析器
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    //从缓存中直接获取这个参数对应的解析器,第一次的话肯定没有
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        //从所有的argumentResolvers里面一个一个找,找到了就放入缓存里,这个缓存将参数作为键,解析器作为值下一调用直接获取
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            //判断此解析器是否支持当前参数,例如参数是否包含某注解,因此对应某解析器,对象参数也有对应的解析器
            if (resolver.supportsParameter(parameter)) {
                result = resolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}
//================第二步:再进入resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory)
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                              NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!关键,这里可以看见我们返回的是mavContainer对象的defaultModel属性
    //无论参数是map还是model还是modelmap,他们的解析器虽然不同,但是resolveArgument()方法都是返回mavContainer.getModel()
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    return mavContainer.getModel();
}
//=================进入mavContainer.getModel()
public ModelMap getModel() {
    //这里可以看见,如果使用的是默认的模型的话,返回的就是mavContainer这个对象的defaultModel属性
    if (useDefaultModel()) {
        return this.defaultModel;
    }
    else {
        if (this.redirectModel == null) {
            this.redirectModel = new ModelMap();
        }
        return this.redirectModel;
    }
}
  • 由上可知,我们参数中map/model最终得到的都是mavContainer这个对象的defaultModel属性,这个属性的类型是BindingAwareModelMap,之前讲过这个BindingAwareModelMap实现了map/model这两个接口,因此返回这个类型我们的map或者model都可以接收。

    • 而且如果我们参数同时有mapmodel,返回的对象实际上是同一个,以为上面可以看到实际上就是调用mavContainer.getModel()返回的,而mavContainer这个对象的创建是在解析参数之前,一次请求映射只会创建一个,因此mavContainer.getModel()返回的是同一个对象。

    • 此时我们使用map或者model添加键值对实际上都会动态绑定到BindingAwareModelMap这个类型调用它的添加方法,因此我们map/model添加的键值对都放在同一个对象里,而这个对象实际上就是mavContainerdefualtModel属性,因此我们添加过后这个属性就有了对应的数据。

    • 例如这样添加

      map.put("1",123);
      model.addAttribute("2",123);
      

      添加过后image-20220516194059723

      • 可以看到defalutModel这个属性有了对应的键值对数据
  • 然后执行完了控制器里面的方法后返回到invocableMethod.invokeAndHandle(webRequest, mavContainer)这一步

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                               HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            //...省略很多
            //这里创建的mavContainer对象
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            //...省略很多
    
            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(logger, traceOn -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
    
            刚刚就是从这里进入的,现在从返回继续执行
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }
    
            //现在进入这里
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
    //===================进入getModelAndView(mavContainer, modelFactory, webRequest)方法
    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
                                         ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    
        modelFactory.updateModel(webRequest, mavContainer);
        if (mavContainer.isRequestHandled()) {
            return null;
        }
        //得到我们操作更新过的模型,如果不是重定向请求就是default这个
        ModelMap model = mavContainer.getModel();
        //将这个mavContainer映射的视图名称和模型数据都作为参数new一个ModelAndView对象出来,这个就是我们最后得到的,这里返回它
        //!!!!!!!!!!!!!!!!!!!!!!!
        ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
        if (!mavContainer.isViewReference()) {
            mav.setView((View) mavContainer.getView());
        }
        if (model instanceof RedirectAttributes) {
            Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            if (request != null) {
                RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
            }
        }
        return mav;
    }
    //之后就是将这个创建出来的mav层层返回直到mv = ha.handle(processedRequest, response, mappedHandler.getHandler())这里
    
  • 至此,我们已经将我们控制器方法里面的键值对添加到了doDispatcher方法里面的mav对象中,之后真正将这个mav对象中的模型数据放到request保存域中的方法是mv = ha.handle(processedRequest, response, mappedHandler.getHandler())之后的processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)这个方法

    image-20220516195845213

    进入processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)方法:

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
    			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
    			@Nullable Exception exception) throws Exception {
        //...省略一些不相关的
        
    		// Did the handler return a view to render?
    		if (mv != null && !mv.wasCleared()) {
                //render方法渲染视图,进入这里!!!!!!!!!!!!!!!!!!!
    			render(mv, request, response);
    			if (errorView) {
    				WebUtils.clearErrorRequestAttributes(request);
    			}
    		}
        //后面的省略
    }
    //========================进入render(mv, request, response);
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		//...省略一些不相关的
    		try {
    			if (mv.getStatus() != null) {
    				request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
    				response.setStatus(mv.getStatus().value());
    			}
                //继续进入这个render方法!!!!!!
    			view.render(mv.getModelInternal(), request, response);
    		}
        	//后面的省略
    }
    //======================进入view.render(mv.getModelInternal(), request, response);
    public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
    			HttpServletResponse response) throws Exception {
    
    		if (logger.isDebugEnabled()) {
    			logger.debug("View " + formatViewName() +
    					", model " + (model != null ? model : Collections.emptyMap()) +
    					(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
    		}
    
    		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
    		prepareResponse(request, response);
        	//这里是重点,进入这个方法!!!!!!!!!!!!!!!!!
    		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    	}
    //=====================进入renderMergedOutputModel(mergedModel, getRequestToExpose(request), response)
    protected void renderMergedOutputModel(
    			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    		// Expose the model object as request attributes.
        	//这里就是暴露mdoel的数据作为RequestAttributes,进去!!!!!!!!!!!!!
    		exposeModelAsRequestAttributes(model, request);
    		//后面的省略
    }
    //====================进去exposeModelAsRequestAttributes(model, request);
    protected void exposeModelAsRequestAttributes(Map<String, Object> model,
                                                  HttpServletRequest request) throws Exception {
    
        //可以看到就是遍历model的每一个键值对,将它用request对象的setAttribute()方法设置
        model.forEach((name, value) -> {
            if (value != null) {
                request.setAttribute(name, value);
            }
            else {
                request.removeAttribute(name);
            }
        });
    }
    
  • 至此分析完毕。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一酒。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值