首页 > 其他分享 >SpringMVC详解

SpringMVC详解

时间:2022-10-31 10:55:58浏览次数:73  
标签:return SpringMVC handler request mavContainer 详解 null response

 SpringMVC的介绍

 【1】Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就已包含在Spring框架中。正式名称“ Spring Web MVC”来自其源模块的名称(spring-webmvc),但它通常被称为“ Spring MVC”。

 

SpringMVC的具体执行流程:

【1】说明:

  1)Spring MVC 是围绕前端控制器模式设计的,其中:中央 Servlet DispatcherServlet 为请求处理流程提供统一调度,实际工作则交给可配置组件执行。这个模型是灵活的且开放的,我们可以通过自己去定制这些组件从而进行定制自己的工作流。

  2)说白了就是用一个DispatcherServlet 封装了一个Servlet的调度中心, 由调度中心帮我们调用我们的处理方法:在这个过程中调度中心委托给各个组件执行具体工作 ,比如帮我们映射方法请求、帮我解析参数、调用处理方法、响应数据和页面 等

【2】图示:

 

 

 

【3】组件说明:

DispatcherServlet: 前端调度器 , 负责将请求拦截下来分发到各控制器方法中
HandlerMapping: 负责根据请求的URL和配置@RequestMapping映射去匹配, 匹配到会返回Handler(具体控制器的方法)
HandlerAdaper: 负责调用Handler-具体的方法-  返回视图的名字  Handler将它封装到ModelAndView(封装视图名,request域的数据)
ViewReslover: 根据ModelAndView里面的视图名地址去找到具体的jsp封装在View对象中
View:进行视图渲染(将jsp转换成html内容 --这是Servlet容器的事情了) 最终response到的客户端

 

【4】流程说明:

1)用户发送请求至前端控制器DispatcherServlet
2)DispatcherServlet收到请求调用处理器映射器HandlerMapping。
    2.1)处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
3)DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter,执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
4)执行处理器Handler(Controller,也叫页面控制器)。
    4.1)Handler执行完成返回ModelAndView
    4.2)HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
5)DispatcherServlet将ModelAndView传给ViewReslover视图解析器
    5.1)ViewReslover解析后返回具体View
6)DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
7)DispatcherServlet响应用户。

 

SpringMVC请求流程图解:

  

 

 

 

执行流程源码解析(我是直接开启SpringBoot里面分析的)

【1】分析主线流程,DispatcherServlet类#doDispatch方法

//DispatcherServlet类#doDispatch方法
//主流程1,执行DispatcherServlet类#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 {
            //检查请求是否是multipart(即文件上传),若是进行相关处理
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            //通过handermapping映射获取HandlerExecutionChain(处理链中包括了interceptor的前置和后置方法)
            //主流程2,获取HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
            // 根据处理器(handler及HandlerExecutionChain)获取处理器适配器(处理器适配器是为了提供统一接口进行后续处理,从而支持多种类型的处理器)
       // 主流程3的具体地方 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //执行chain中拦截器附加的预处理方法,即preHandle方法  if (!mappedHandler.applyPreHandle(processedRequest, response)) { // 返回false就不进行后续处理了 return; } // 执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作 ,主流程4的具体地方 // 执行处理器Handler(Controller,也叫页面控制器)。 // Handler执行完成返回ModelAndView // HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } // 如果没有视图,给你设置默认视图 json忽略 applyDefaultViewName(processedRequest, mv); // 后置拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } // DispatcherServlet将ModelAndView传给ViewReslover视图解析器 // ViewReslover解析后返回具体View // DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。 // DispatcherServlet响应用户。 // 如果有异常,还会处理异常 ,主流程5,6的具体地方 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //拦截器afterCompletion处理器 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }

 

【2】分析getHandler方法如何返回 处理器执行链HandlerExecutionChain

//分析getHandler
//this.handlerMappings的内容
//0.RequestMappingHandlerMapping
//1.BeanNameUrlHandlerMapping
//2.RouterFunctionMapping
//3.SimpleUrlHandlerMapping
//4.WelcomePageHandlerMapping
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

//调用到了AbstractHandlerMapping类#getHandler方法
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //getHandlerInternal(request)方法为抽象方法,供子类实现
    //获取到的handler对象一般为bean/HandlerMethod
    Object handler = getHandlerInternal(request);
    //上述找不到则使用默认的处理类,没有设定则返回null,则会返回前台404错误
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // Ensure presence of cached lookupPath for interceptors and others
    if (!ServletRequestPathUtils.hasCachedPath(request)) {
        initLookupPath(request);
    }
    //创建处理链对象
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    //针对cros跨域请求的处理
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = getCorsConfiguration(handler, request);
        if (getCorsConfigurationSource() != null) {
            CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
            config = (globalConfig != null ? globalConfig.combine(config) : config);
        }
        if (config != null) {
            config.validateAllowCredentials();
        }
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

【2.1】分析AbstractHandlerMapping类#getHandler方法

【2.1.1】如何获取handler对象【一般为bean/HandlerMethod】

//RequestMappingInfoHandlerMapping类#getHandlerInternal方法
//因为它是RequestMappingHandlerMapping的父类
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    try {
        //调用父类AbstractHandlerMethodMapping类
        return super.getHandlerInternal(request);
    }
    finally {
        ProducesRequestCondition.clearMediaTypesAttribute(request);
    }
}

//调用到AbstractHandlerMethodMapping类getHandlerInternal方法
//针对HandlerMethod的获取
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取访问的路径,一般类似于request.getServletPath()返回不含contextPath的访问路径
    String lookupPath = initLookupPath(request);
    //获取读锁
    this.mappingRegistry.acquireReadLock();
    try {
        //获取HandlerMethod作为handler对象,这里涉及到路径匹配的优先级
        //优先级:精确匹配>最长路径匹配>扩展名匹配
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        //HandlerMethod内部含有bean对象,其实指的是对应的Controller
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        //释放读锁
        this.mappingRegistry.releaseReadLock();
    }
}

【2.1.2】如何创建处理链

//创建处理器链的方法
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    /创建HandlerExecutionChain
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    //与请求url进行匹配,满足的才加入
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(request)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

 

【3】分析getHandlerAdapter寻找的处理器适配器

//分析getHandlerAdapter
//this.handlerAdapters的内容
//0.RequestMappingHandlerAdapter
//1.HandlerFunctionAdapter
//2.HttpRequestHandlerAdapter
//3.SimpleControllerHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {
                //所以一般返回的也就是RequestMappingHandlerAdapter
                return adapter;
            }
        }
    }
    throw new ServletException(...);
}

//因为RequestMappingHandlerAdapter没有重写故调用父类的
//调用AbstractHandlerMethodAdapter类#supports方法
@Override
public final boolean supports(Object handler) {
    //如果是类的方法的话默认是true
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

 

【4】分析mappedHandler.applyPreHandle前置处理器与mappedHandler.applyPostHandle后置处理器

//分析mappedHandler.applyPreHandle前置处理器与mappedHandler.applyPostHandle后置处理器
//前置处理器是从0到size
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
        }
        this.interceptorIndex = i;
    }
    return true;
}

//前置处理器是从size到0
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {

    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

 

【5】分析ha.handle(processedRequest, response, mappedHandler.getHandler());,如何进行调用控制器里面的方法

//AbstractHandlerMethodAdapter类#handle方法
//因为适配器RequestMappingHandlerAdapter类没有所以定位到了父类
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return handleInternal(request, response, (HandlerMethod) handler);
}

//RequestMappingHandlerAdapter类#handleInternal方法
@Override
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    // 检查当前请求的method是否为支持的method(默认Null,可通过继承AbstractController设置supportedMethods)
    // 检查当前请求是否必须session  (默认false,可通过继承AbstractController设置requireSession)
    checkRequest(request);

    /**
    * 判断当前是否需要支持在同一个session中只能线性地处理请求
    * 因为锁是通过 synchronized 是 JVM 进程级,所以在分布式环境下,
    * 无法达到同步相同 Session 的功能。默认情况下,synchronizeOnSession 为 false
    */
    if (this.synchronizeOnSession) {
        // 获取当前请求的session对象
        HttpSession session = request.getSession(false);
        if (session != null) {
            // 为当前session生成一个唯一的可以用于锁定的key
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                // 对HandlerMethod进行参数等的适配处理,并调用目标handler
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // 如果当前不存在session,则直接对HandlerMethod进行适配
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // 这般都会走这里,重点反射调用
        // 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
    //判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理    
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        // 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。
        // 这里SessionAttribute主要是通过@SessionAttribute注解生成的
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            // 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,
            // 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的
            // Cache的过期时间为-1,即立即失效
            prepareResponse(response);
        }
    }

    return mav;
}

【5.1】分析invokeHandlerMethod方法怎么做【先是参数处理器,再是生成容器,然后去反射调用,最后将结果放入容器

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // 把我们的请求req resp包装成 ServletWebRequest
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中
        // 配置的InitBinder,用于进行参数的绑定
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller 中配置的ModelAttribute,
        // 这些配置的方法将会在目标方法调用之前进行调用
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // 封装handlerMethod,会在调用前解析参数、调用后对返回值进行处理
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) {
            // 让invocableMethod拥有参数解析能力
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
            // 让invocableMethod拥有返回值处理能力
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 让invocableMethod拥有InitBinder解析能力
        invocableMethod.setDataBinderFactory(binderFactory);
        // 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        // 创建ModelAndView处理容器
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 将request的Attribute复制一份到ModelMap
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 调用我们标注了@ModelAttribute的方法,主要是为我们的目标方法预加载
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        // 重定向的时候,忽略model中的数据 默认false
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        // 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标
        // handler的返回值是否为WebAsyncTask或DeferredResult,如果是这两种中的一种,
        // 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中
        // 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。
        // 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,提高吞吐。
        // 只有待目标任务完成之后才会回来将该异步任务的结果返回。
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
        // 封装异步任务的线程池、request、interceptors到WebAsyncManager中
        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);
        }
        // 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        // 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,还会判断是否需要将FlashAttributes封装到新的请求中
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

 

【5.1.1】分析invocableMethod.invokeAndHandle怎么反射调用

//ServletInvocableHandlerMethod类#invokeAndHandle方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 真正的调用我们的目标对象
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 设置相关的返回状态
    setResponseStatus(webRequest);
    // 如果请求处理完成,则设置requestHandled属性
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    // 如果请求失败,但是有错误原因,那么也会设置requestHandled属性
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }

    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 遍历当前容器中所有ReturnValueHandler,判断哪种handler支持当前返回值的处理,
        // 如果支持,则使用该handler处理该返回值
        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        throw ex;
    }
}

//InvocableHandlerMethod类#invokeForRequest方法
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 获取我们目标方法入参的值
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    // 反射调用 ,里面主要就是 method.invoke(getBean(), args) 来进行反射调用
    return doInvoke(args);
}

 

【5.1.2】分析 对封装的ModelAndView进行处理

//RequestMappingHandlerAdapter类#getModelAndView方法
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
        ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

    modelFactory.updateModel(webRequest, mavContainer);
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    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<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
    }
    return mav;
}

 

【6】分析processDispatchResult方法对返回结果的处理

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {

    boolean errorView = false;
    // 异常处理
    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 (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        // Exception (if any) is already handled..
     // 拦截器的后置处理 mappedHandler.triggerAfterCompletion(request, response, null); } }

 

【6.1】分析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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);

    View view;
    String viewName = mv.getViewName();
    if (viewName != null) {
        // 解析视图名
        view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
        if (view == null) {
            throw new ServletException(...);
        }
    }
    else {
        // No need to lookup: the ModelAndView object contains the actual View object.
        view = mv.getView();
        if (view == null) {  throw new ServletException(...);  }
    }

    // Delegate to the View object for rendering.

    try {
        if (mv.getStatus() != null) {
            request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
            response.setStatus(mv.getStatus().value());
        }
        // 进行视图渲染 ,调用的是 AbstractView类的方法
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) { throw ex; }
}

 

源码解析注解@RequestMapping

【1】@RequestMapping解析

【1.1】说明:

  1)明确一点:@RequestMapping是通过RequestMappingHandlerMapping负责解析。

  2)HandlerMapping便是负责根据请求URI 映射 到对应的handler方法。而RequestMappingHandlerMapping是HandlerMapping的其中一个实现类, 负责根据@RequestMapping注解进行映射。

  3)所以HandlerMapping有很多其他实现类,RequestMappingHandlerMapping是最常用的。HandlerMapping可分为2个过程:1解析、2映射

【1.2】分析RequestMappingHandlerMapping类

  1)基于继承关系可以发现它实现了InitializingBean接口

  2)分析afterPropertiesSet方法做了什么

@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {
    //这里都是一些设置配置
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setTrailingSlashMatch(useTrailingSlashMatch());
    this.config.setContentNegotiationManager(getContentNegotiationManager());

    if (getPatternParser() != null) {
        this.config.setPatternParser(getPatternParser());
    }
    else {
        this.config.setSuffixPatternMatch(useSuffixPatternMatch());
        this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
        this.config.setPathMatcher(getPathMatcher());
    }
    //调用父类AbstractHandlerMethodMapping类的afterPropertiesSet方法
    super.afterPropertiesSet();
}

//父类AbstractHandlerMethodMapping类的afterPropertiesSet方法
public void afterPropertiesSet() {
    initHandlerMethods();
}

//AbstractHandlerMethodMapping类#initHandlerMethods方法
protected void initHandlerMethods() {
    // 获得所有候选beanName—— 当前容器所有的beanName
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            // 处理候选bean——即解析@RequestMapping和映射路径
            processCandidateBean(beanName);
        }
    }
    // 解析完所有@RequestMapping的时候调用,输出日志
    handlerMethodsInitialized(getHandlerMethods());
}

 

【1.2.1】分析processCandidateBean方法怎么处理的

protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {..省略日志..}
    // 这一步判断是关键  是否有Controller 或 RequestMapping注解
    if (beanType != null && isHandler(beanType)) {
        // 解析HandlerMethods
        detectHandlerMethods(beanName);
    }
}

protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 循环所有方法
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                (MethodIntrospector.MetadataLookup<T>) method -> {
                    try {
                        return getMappingForMethod(method, userType);
                    }
                    catch (Throwable ex) {..省略异常..}
        });
        ..省略日志..
        //循环注册
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

【1.2.1.1】解析流程

//调用回子类RequestMappingHandlerMapping类#getMappingForMethod方法
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 如果方法上面有@RequestMapping:解析出RequestMappingInfo
    // RequestMappingInfo 是用来在请求的时候做匹对的
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 如果方法上面有@RequestMapping,看看类上面是不是有@RequestMapping
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        // 类上面也有@RequestMapping  那就合并
        // 比如 类:/user  方法:/info 合并为 /user/info
        if (typeInfo != null) {
            info = typeInfo.combine(info);
        }
        // 合并前缀   5.1新增  默认null
        // 可通过 WebMvcConfigurer#configurePathMatch 进行定制
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
        }
    }
    return info;
}

 

【1.2.1.2】注册流程

//调用回子类RequestMappingHandlerMapping类#registerHandlerMethod方法
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
    super.registerHandlerMethod(handler, method, mapping);
    updateConsumesCondition(mapping, method);
}
//父类AbstractHandlerMethodMapping类#registerHandlerMethod方法
//其中private final MappingRegistry mappingRegistry = new MappingRegistry();
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}

//两大存储容器
//private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
//private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
//pathLookup存储【path, mapping】
//registry存储【mapping,与之对应的【mapping, handlerMethod, directPaths, name, corsConfig】】

public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        validateMethodMapping(handlerMethod, mapping);

        Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
        for (String path : directPaths) {
            this.pathLookup.add(path, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            corsConfig.validateAllowCredentials();
            this.corsLookup.put(handlerMethod, corsConfig);
        }

        this.registry.put(mapping,
                new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

 

【2】@RequestMapping请求映射

【2.1】回看执行流程的【2.1.1】中的getHandlerInternal方法

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 通过UrlPathHelper对象,用于来解析从们的request中解析出请求映射路径
    String lookupPath = initLookupPath(request);
    //获取读锁
    this.mappingRegistry.acquireReadLock();
    try {
        // 通过lookupPath解析最终的handler——HandlerMethod对象
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        //释放读锁
        this.mappingRegistry.releaseReadLock();
    }
}

//分析查找流程
//先从pathLookup里面拿
//拿不到再去进行通配符匹配,排序获取第一个最优匹配的
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 根据uri从mappingRegistry.pathLookup获取 RequestMappingInfo
    // pathLookup<path,RequestMappingInfo>会在初始化阶段解析好
    List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
    if (directPathMatches != null) {
        // 如果根据path能直接匹配的RequestMappingInfo 则用该mapping进行匹配其他条件(method、header等)
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 如果无path匹配,用所有的RequestMappingInfo  通过AntPathMatcher匹配
        addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
    }
    if (!matches.isEmpty()) {
        // 选择第一个为最匹配的
        Match bestMatch = matches.get(0);
        /**
         * 如果匹配到多个
         @RequestMapping(value="/mappin?")
         @RequestMapping(value="/mappin*")
         @RequestMapping(value="/{xxxx}")
         @RequestMapping(value="/**")
         */
        if (matches.size() > 1) {
            //创建MatchComparator的匹配器对象
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));

            /** 根据精准度排序  大概是这样的: ? > * > {} >**   具体可以去看:
             * @see org.springframework.util.AntPathMatcher.AntPatternComparator#compare(java.lang.String, java.lang.String)*/
            matches.sort(comparator);

            // 排完序后拿到优先级最高的
            bestMatch = matches.get(0);

            // 是否配置CORS并且匹配
            if (CorsUtils.isPreFlightRequest(request)) {
                for (Match match : matches) {
                    if (match.hasCorsConfig()) {
                        return PREFLIGHT_AMBIGUOUS_MATCH;
                    }
                }
            }
            else {
                //获取第二最匹配的
                Match secondBestMatch = matches.get(1);
                //若第一个和第二个是一样的 抛出异常
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.getHandlerMethod().getMethod();
                    Method m2 = secondBestMatch.getHandlerMethod().getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException(...);
                }
            }
        }
        //把最匹配的设置到request中
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
        handleMatch(bestMatch.mapping, lookupPath, request);
        //返回最匹配的
        return bestMatch.getHandlerMethod();
    }
    else { // return null
        return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
    }
}

 

【2.1】期待后面继续补充吧

标签:return,SpringMVC,handler,request,mavContainer,详解,null,response
From: https://www.cnblogs.com/chafry/p/16840267.html

相关文章

  • mysql事务实现原理详解
    说说MySQL中的RedologUndolog都在干啥undo日志用于存放数据修改被修改前的值,假设修改tba表中id=2的行数据,把Name='B'修改为Name='B2',那么undo日志就会用来存放Nam......
  • Latex Table 合并行/列详解
    1.整体逻辑整个table是由大小一致的单元格组成的,在这个基础上,我们通过合并单元格(行/列)的方式,实现整个table的设计:竖线用“|”,横线用“\cline“,列合并用”\multicolumn“,......
  • ORM查询方法详解
    ORM查询方法 ......
  • Memcache详解
    Memcache详解参考链接https://blog.51cto.com/freeloda/1289806https://acecodeinterview.com/memcached/https://hoverzheng.github.io/post/technology-blog/archite......
  • Android SharePreference框架Favor详解
    Favor封装了SharePreference,以注解的方式使用SP。地址:http://cocosw.com/Favor/Favor框架一共提供了四个注解:##1.AllFavor源码如下,标记一个类的所有的字段都被Favor管理......
  • php yield详解
     一.介绍  二.简单例子//包含yield的函数可以生成一个generator对象,可以被foreach遍历functionGenerator(){for($i=0;$i<3;$i++){echo"输出存在......
  • C语言之指针详解
    目录1指针1.1简介1.2什么是指针1.3使用指针1.3.1简单使用1.3.2NULL指针1.3.3指针算术运算1.3.3.1定义1.3.3.2遍历数组:递增一个指针1.3.3.3遍历数组:递减一个指针......
  • RSA算法详解
    基础知识RSA设计\(m^{ed}\equiv1\:(mod\:n)\)RSA密钥生成第一步,随机选择两个不相等的质数p和q。如61和53。(质数越大越安全。)第二步,计算p和q的乘积n。把61和5......
  • SSM框架(spring+springmvc+mybatis)+Mysql实现的社区物业管理系统(功能包含分角色,报修
    (博客目录)SSM框架(spring+springmvc+mybatis)+Mysql实现的社区物业管理系统本系统为了解决线下物业管理小区的冗余繁杂的难题,通过整合业主和物业,将平时的业务在线化,节省......
  • SSM框架(spring+springmvc+mybatis)+layui+Mysql实现的停车位租赁系统(功能包含注册登
    (博客目录)SSM框架(spring+springmvc+mybatis)+layui+Mysql实现的停车位租赁系统本系统为了解决停车位租赁不透明的难题,提供了一个连接租客和车位主的一个平台,通过不同角......