springboot-请求处理源码分析(三)解析Map,Model参数

springboot-请求处理源码分析(三)解析Map,Model参数,第1张

springboot-请求处理源码分析(三)解析Map,Model参数

复杂参数的请求处理的源码分析:

Dbug分析:Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)

//前面Dbug个模式省略,直接看一些重要的底层代码
//获取能够处理器Map model的解析器
@Override
public boolean supportsParameter(MethodParameter parameter){
    parameter.getParameterAnnotations().length==0;
}
//解析器解析
@Override
@Nullable
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");
    return mavContainer.getModel();
}
public ModelMap getModel(){
    if(useDefaultModel()){
        retrun this.defaultModel;
    }
    省略后面源码...
}
private final ModeMap defaultModel = new BindingAwareModelMap();

//第二次循环Model的时候,也在底层调用了这个方法,说明Map和Model都会返回 BindingAwareModelMap
@Override
@Nullable
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");
    return mavContainer.getModel();
}

Dbug分析调试一些重要的参数

 执行:invokeForRequest方法
----------->doInvoke(args);
//真正执行目标反复噶

@Nullable
protected Object doInvoke(Object... args) throws Exception {
//执行源代码,就是你编写的代码(业务逻辑代码)
ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        return getBridgedMethod().invoke(getBean(), args);
    }
省略部分源码...

获取方法的返回值:returnValue ,获取请求准发的地址:"/table"

获取保存的属性值:mavContainer

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //returnValue可以获取到当前方法的处理结果:"/table"请求转发
        //mavContainer可以获取到属性内保存的参数值
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		//设置响应状态
        setResponseStatus(webRequest);
//省略部分源码...            
            //处理返回结果
            //mavContainer保存属性和属性值
            //Dbug调试
			this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}

--------------------------------------------------------------------------
//处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    //找到返回值的处理器
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    //继续深入源码,查看如何处理返回值
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
--------------------------------------------------------------------------
//处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    //如果returnValue(里面保存里返回结果"/table")
    //如果不存在返回结果,那么就将true保存在mvcContainer
    
    if (returnValue == null) {
        mavContainer.setRequestHandled(true);
    return;
    }
    //将当前的returnValue转化为ModelAndView
    ModelAndView mav = (ModelAndView) returnValue;
    if (mav.isReference()) {
        String viewName = mav.getViewName();    //"/table"
        mavContainer.setViewName(viewName);     //将结果放入到mavContainer当中
	    ...
}

目标方法执行结束之后,将所有的数据放在ModelAndViewContaioner;

包含要去的页面地址view,还有Modl数据

//模型工厂
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    //更新Model
    modelFactory.updateModel(webRequest, mavContainer);
   
//绑定策略
private void updateBindingResult(NativeWebRequest request, ModelMap model) throws Exception {
    List keyNames = new ArrayList<>(model.keySet());
    for (String name : keyNames) {
        Object value = model.get(name);
        if (value != null && isBindingCandidate(name, value)) {
            String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + name;
            if (!model.containsAttribute(bindingResultKey)) {
                WebDataBinder dataBinder = this.dataBinderFactory.createBinder(request, value, name);
                model.put(bindingResultKey, dataBinder.getBindingResult());
            }
        }
    }
}
//再次封装
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			             ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    modelFactory.updateModel(webRequest, mavContainer);
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    //model 保存的是当前对象的属性和值(k,v)
    //再次封装为mav
    ModelMap model = mavContainer.getModel();
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }
    //判断当前数据是否为重定向数据
    if (model instanceof RedirectAttributes) {
        Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
    }
    return mav;
}
//之后这个方法算是执行完毕,返回到RequestMappingHandlerAdapter.java
//mav = invokeHandlerMethod(request, response, handlerMethod);
//然后继续执行,返回到
//DispatcherServlet.java
//当前方法也执行完毕:(真正使用适配器执行目标方法也真正结束了)
//mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//继续进入下一个核心代码
//mappedHandler.applyPostHandle(processedRequest, response, mv);

DispatcherServlet.java

核心方法:mappedHandler.applyPostHandle(processedRequest, response, mv);

//执行拦截器方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
		     throws Exception {

    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = interceptors.length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = interceptors[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }
}
//省略部分源码...
//处理最终的结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
//做错误处理性格的返回false,继续向下执行
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			           @Nullable Exception exception) throws Exception {
    boolean errorView = false;
    //省略部分源码...
}
//省略部分源码...
// Did the handler return a view to render?
//当前mv保存了属性和属性值,以及请求地址"/table"
if (mv != null && !mv.wasCleared()) {
//要去那个页面,开始渲染
//Dbug调试,继续深入源码
render(mv, request, response);
//省略部分源码...

 继续深入源码,看如何渲染页面的

//深入源码查看是如何渲染的
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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);
    View view;
    //获取视图名viewName="/table"
    String viewName = mv.getViewName();
    if (viewName != null) {
        // We need to resolve the view name.
        //解析视图
        //Dbug调试mv.getModelInternal()
        //结果为:参数和参数值  map  map...    model  model...
        //深入源码查看是如何解析的
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
//省略部分源码...        
//进入视图解析器进行解析
@Nullable
protected View resolveViewName(String viewName, @Nullable Map model,
                               Locale locale, HttpServletRequest request) throws Exception {
    if (this.viewResolvers != null) {
        for (ViewResolver viewResolver : this.viewResolvers) {
        //继续查看是如何解析的
        View view = viewResolver.resolveViewName(viewName, locale);
//省略部分源码...
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
    //拿到请求域中的全部属性
    RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
    //省略部分源码...
}
//省略部分源码...
//核心代码
View view = viewResolver.resolveViewName(viewName, locale);
Map mergedModel = createMergedOutputModel(model, request, response);、
//继续进入源码代码,继续查看
protected Map createMergedOutputModel(@Nullable Map model,
			                              HttpServletRequest request, HttpServletResponse response) {

    @SuppressWarnings("unchecked")
    Map pathVars = (this.exposePathVariables ?
    (Map) request.getAttribute(View.PATH_VARIABLES) : null);

    // Consolidate static and dynamic model attributes.
    int size = this.staticAttributes.size();
    size += (model != null ? model.size() : 0);
    size += (pathVars != null ? pathVars.size() : 0);
    //声明:mergedModel
    Map mergedModel = new linkedHashMap<>(size);
    mergedModel.putAll(this.staticAttributes);
    if (pathVars != null) {
        mergedModel.putAll(pathVars);
    }
    //如果当前数据不为空,将当前的数据转移的linkedHashMap
    if (model != null) {
        mergedModel.putAll(model);
    }

    // Expose RequestContext?
    if (this.requestContextAttribute != null) {
        mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
    }
    //最终得到这个linkedHashMap
    return mergedModel;
}

//继续执行代码,跳转到AbstractView.java
//Dbug调试mergedModel 里面保存的了方法的参数值   map  map...    model  model...
Map mergedModel = createMergedOutputModel(model, request, response);
//准备响应
prepareResponse(request, response);
//渲染合并输出的模型数据
//我们将model中的数据放入到mergedModel,然后有放入到了renderMergedOutputModel()方法里面
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
@Override
protected void renderMergedOutputModel(
    Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {

    // Expose the model object as request attributes.
    //暴露模型作为请求域的属性
    //Dbug调试,查看是如何将Map和Model放入的request作用域当中的
    exposeModelAsRequestAttributes(model, request);

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

    // Determine the path for the request dispatcher.
    String dispatcherPath = prepareForRendering(request, response);

    // Obtain a RequestDispatcher for the target resource (typically a JSP).
    RequestDispatcher rd = getRequestDispatcher(request, 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(request, response)) {
        response.setContentType(getContentType());
        if (logger.isDebugEnabled()) {
            logger.debug("Including [" + getUrl() + "]");
        }
        rd.include(request, response);
    }

    else {
        // Note: The forwarded resource is supposed to determine the content type itself.
        if (logger.isDebugEnabled()) {
            logger.debug("Forwarding to [" + getUrl() + "]");
        }
        rd.forward(request, response);
    }
}

Dbug调试:如何将Model Map放入的request集合中去的

protected void exposeModelAsRequestAttributes(Map model,
			                      HttpServletRequest request) throws Exception {

    model.forEach((name, value) -> {
    if (value != null) {
        request.setAttribute(name, value);
    }
    else {
        request.removeAttribute(name);
    }
    });
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719467.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存