盘点 SpringMVC : MVC 主流程

盘点 SpringMVC : MVC 主流程

一 . 前言

文章目标 :

  • 梳理 SpringMVC 主流程中的相关逻辑
  • 确定 相关流程得参数

本文章未涉及的部分:

  • MVC 的配置
  • 容器的初始化
  • 容器的加载
  • 等….

二 . 流程分析

此主要流程包括如下几个部分 :

  • 注解的扫描处理
  • 请求的拦截
  • 请求的转换
  • 请求的最终处理
SpringMVC.jpg

2.1 注解的扫描处理

注解的扫描主要在 DispatcherServlet.initHandlerMappings 中 , 其逻辑处理类在 AbstractHandlerMethodMapping.getHandlerInternal 中.

2.1.1 注解的扫描

注解扫描的起点主要是 RequestMappingHandlerMapping , 其中做了这几件事 :

  • 在 AbstractHandlerMethodMapping 中通过 InitializingBean 的 afterPropertiesSet 处理所有的方法
    • detectHandlerMethods 中进行核心的处理
  • 对 RequestMapping 进行了扫描操作 , 并且生成 RequestMappingInfo

C31- RequestMappingHandlerMapping : 扫描的起点 , 因为类实现了 InitializingBean 接口 , 其核心基于 afterPropertiesSet
    M- afterPropertiesSet
        ?- 这个方法中主要对  RequestMappingInfo.BuilderConfiguration 进行配置 ,最后调用父类 afterPropertiesSet 方法
    
C32- AbstractHandlerMethodMapping
    M32_01- afterPropertiesSet
        - initHandlerMethods() : 核心方法 , 对 Handler Method 进行处理 -> M32_02
    M32_02- initHandlerMethods 
        ?- 扫描ApplicationContext中的bean,检测和注册处理程序方法
        - 获取所有的 BeanName , 调用 processCandidateBean 执行 -> M32_03
    M32_03- processCandidateBean
        - obtainApplicationContext().getType 获取具体的 Class 类
        - 通过 isHandler 判断是否包含 Controller 或者 RequestMapping 
            ?- RestController 继承了 Controller
            - 如果需要处理 , 调用 detectHandlerMethods 处理 -> M32_04
    M32_04- detectHandlerMethods
        - 同样的 , 通过传入的 handle (类的别名) 获取对应的 Class<?>
        - 获取所有的标注了注解的集合 Map<Method, T> -> ps:M32_04_01
            - getMappingForMethod 获取注解对应的 Condition -> ps:M32_04_01 详细流程
            - selectMethods
        FOR- 循环所有的 methods , 首先搜索可用的代理 , 注册对应的 Bean
            ?- 代理是 Spring 中很重要的一环 , 后面开单章详细说
    M32_05- registerHandlerMethod
        - 注册到 MappingRegistry
                
            
// ps:M32_04_01 流程详细分析
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {
    return getMappingForMethod(method, userType);
});

// 可以看到 , 其中核心的方法有2个 getMappingForMethod / selectMethods
getMappingForMethod 会返回Mapping 对应的 Condition , 例如 patternsCondition / methodCondition
    

// ps:M32_04_01
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 此处对 RequestMapping 进行了扫描操作
    // 代码比较简单 , 就是 AnnotatedElementUtils.findMergedAnnotation 后构建了一个 RequestMappingInfo bean
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 此处是获取 Class 类上面的 RequestMapping
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
             // 对2者进行组合 , 生成新的 Bean 对象
             // 注意是类 组合 方法
             // 主要是覆盖和合并 , url 比较特殊 , 变化为 /get -> /cookie/get
            info = typeInfo.combine(info);
        }
        
        // 前缀 path 的处理 , 该属性在配置 PathMatchConfigurer 时处理 , 可以通过 addPathPrefix 添加
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
        }
    }
    return info;
}       

2.1.2 Bean 的注册

上面的环节已经对 Mapping Method 扫描完成 , 在此环节中进行注册 , 注册主要使用内部类MappingRegistry , 其内部存在多个 Map ,用于保存地址的映射关系

(url -MappingRegistration/HandlerMethod/CorsConfiguration 等 )

            
C- AbstractHandlerMethodMapping
    VC33- MappingRegistry : 内部类 
        F33_01- Map<T, MappingRegistration<T>> registry = new HashMap<>();
        F33_02- Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
        F33_03- MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
        F33_04- Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
        F33_05- Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
        M33_01- register(T mapping, Object handler, Method method)  -> PS:M33_01
            ?- 此处主要是为了构建 Map 集合 , 用于映射时匹配
            1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
            2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合 
            3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
            4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04) -> PS:M33_02
            5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
            6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry (F33_01)
            
        
// PS:M33_01 register 方法的关键和亮点
1- 使用 ReentrantReadWriteLock  保证多线程下访问的唯一性 , 在 finally 中解锁

// PS:M33_02 特殊的命名方式 RequestMappingInfoHandlerMethodMappingNamingStrategy
这里主要通过 RequestMappingInfoHandlerMethodMappingNamingStrategy 类生成对应的 Name
    
    
// M33_01 伪代码
public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        // 1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        validateMethodMapping(handlerMethod, mapping);
        
        // 2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合 
        this.mappingLookup.put(mapping, handlerMethod);

        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            // 3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            // 4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04) 
            addMappingName(name, handlerMethod);
        }
        
        // 构建跨域配置
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        // 6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }finally {
        this.readWriteLock.writeLock().unlock();
    }
}
    

// 自此 , Mapper 的前期准备就完成了 
MvcUrl001.jpg
HandlerMappingCondition.jpg

2.2 请求的来临

请求的入口还是通过 Servlet 来完成的 , 先看一下 Servlet 体系 PS:51_01

2.2.1 起点 : 初始化一个 Servlet

MVC 是基于 Servlet 的体系结构 , 其最初的起点是通过 StandardWrapper 进行 initServlet 开始 流转路径如下 :

StandardWrapper -> GenericServlet (init) -> HttpServletBean (init) -> FrameworkServlet (initServletBean)

看一个很老的图 , 大概对 DispatcherServlet 有个初步的了解 :

mvc-context-hierarchy.png

2.2.2 核心 : DispatchServlet 的初始化

C51- DispatcherServlet 
    M51_10- initHandlerMappings(ApplicationContext context)
        ?- 这个方法的核心操作就是初始化 handlerMappings -> PS:M51_10_01
        - 通过 BeanFactoryUtils 构建所有的 Mapping 类型结合  
        - 为 Map 进行排序

Filter 处理逻辑 , Filter 分为 3步 : 初始化 , 拦截 , 销毁 , 此处主要是初始化操作 >>

Filter 不是 Spring 专属的对象 , 其归属于 Servlet 原生体系 , 主要有以下2个流程


子流程一 : 核心处理容器 : StandardContext,添加 Filter 流程

  • ServletWebServerApplicationContext # selfInitialize : 获取所有的需要处理的 Filter 类
  • ServletContextInitializerBeans # ServletContextInitializerBeans : 从 Factory 中获取具体的类
  • RegistrationBean # onStartup : 启动 并且注册 FilterBean
  • StandardContext # addFilterDef : 添加 FilterDef , 即 filter definition
                  
C- ServletWebServerApplicationContext
    M- selfInitialize
        - getServletContextInitializerBeans 其中会获取所有的 Beans  , 分别调用 beans.onStartup 启动
    M- getServletContextInitializerBeans
        - 核心处理逻辑在 ServletContextInitializerBeans 中
            
C- ServletContextInitializerBeans
    M- ServletContextInitializerBeans(ListableBeanFactory beanFactory,Class<? extends ServletContextInitializer>... initializerTypes)
        ?- 此方法中会获取 Servlet 和 Filter 的初始化类 --> TODO : 后续单独分析 Serlvet 时看

子流程二 : 调用 Filter 初始化流程

这是一个异步操作 : 通过一个 call 流程异步处理 , 具体的流程在 org.apache.catalina.core 中

  • StandardContext # filterStart : Set filterDefs.entrySet 中获取所有的 Filter
  • ApplicationFilterConfig : 构建一个 ApplicationFilterConfig 并且在其中调用 initFilter() 初始化
            
// Filter 的拦截调用
Filter 的核心思路就是 FilterChain 的链表调用 . 其起点为  ApplicationFilterChain 
C- ApplicationFilterChain
    F- private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
        - 选择一个 ApplicationFilterConfig , 调用 doFilter , 并且把当前对象传入
             ?- 后续就是调用链的逻辑
            
            
            
            
// HandlerInterceptor 的处理流程
- 与 Filter 不同的是 , 这里的 HandlerInterceptor 是 Spring 体系中的对象
- 拦截器主要在 WebMvcConfigurer 通过 InterceptorRegistry 手动注入             

@Override
public void addInterceptors(InterceptorRegistry registry) {
    logger.info("------> this is addInterceptors  <-------");
    registry.addInterceptor(new ConfigInterceptor());
}

// Interceptor 的初始化
Interceptor 的主要起点是 WebMvcConfigurationSupport
C- WebMvcConfigurationSupport
    M- requestMappingHandlerMapping
        - 其中会为当前 Mapping 添加 Interceptor

    
// Interceptor 的调用
Interceptor 的主调流程位于 HandlerExecutionChain
C- HandlerExecutionChain
    M- applyPreHandle
        - getInterceptors() 获取 HandlerInterceptor->LV001 数组
        FOR- 循环 HandlerInterceptor:LV001 调用 preHandle
            

// DispatcherServlet 衔接到 RequestMapping 映射关联
- ApplicationFilterChain 处理完成 Filter 
//  这里会进行一次继承类的循环调用
C- DispatcherServlet
    M- FrameworkServlet
        M- HttpServlet
            
- HttpServlet 执行 service(ServletRequest req, ServletResponse res) 方法
- FrameworkServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法        
- HttpServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法
- FrameworkServlet 执行 doGet 处理请求
- FrameworkServlet 执行 processRequest 开始完整处理
- 来到具体实现类 DispatcherServlet 

PS:51_01 Servlet 家族体系 ServletModule.png

PS:M51_10_01 HandlerMapping 家族体系 HandlerMappingModule.png

2.3 请求的解析

servlet 的起始方法是 HttpServlet , Spring 部分的核心方法是实现类FrameworkServlet

解析前置处理操作

  • 在 Reuqest 和 Response 转换为 HttpServletRequest 和 HttpServletResponse 后
  • 调用 HttpServlet 中 service(HttpServletRequest req, HttpServletResponse resp) 方法 , 触发 FrameworkServlet doGet 方法
  • 最终进入 DispatcherServlet 核心类 , 处理一个 Http 请求

2.3.1 DispatcherServlet 获取处理 Handler

Start -> HttpServlet
// TODO : Dispatch 具体流程以后单独分析 , 这里先简单过一下
C51- DispatcherServlet 
    M51_01- doService(HttpServletRequest request, HttpServletResponse response)
        ?- 执行 Service 处理请求
        - 调用 M51_02 执行具体的流程
    M51_02- doDispatch(HttpServletRequest request, HttpServletResponse response)
        1- WebAsyncUtils.getAsyncManager(request) : 准备异步处理管理器 WebAsyncManager -> PS:M51_02_01
        2- checkMultipart(request) : 尝试解析 Multipart Request -> PS:M51_02_02
        3- getHandler(processedRequest) : 获取具体需要执行的 Handler -> M51_03
            ?- 未找到对应的 Handler 会直接 return
        4- getHandlerAdapter(mappedHandler.getHandler()) : 确定当前请求的处理程序适配器 -> PS:M51_02_04
        5- 处理 Get-Head 请求 -> PS:M51_02_05
        - mappedHandler.applyPreHandle : 前置处理
        6- 调用 HandlerAdapter 处理 请求
        7- applyDefaultViewName : view 名称的解析 , 此环节不分析
        - mappedHandler.applyPostHandle : 后置处理 -> PS:M51_02_09
    M51_03- getHandler
    M51_04- getHandlerAdapter    

// M51_03 源代码
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;
}


//  M51_04 getHandlerAdapter 源代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 太常见的处理方式 , 循环处理中通过 support 判断
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("....");
}

PS:M51_02_01 WebAsyncManager 介绍

  • 作用 : 用于管理异步请求处理的中心类,主要用作SPI,通常不被应用程序类直接使用
  • 核心 : 通过多个不同的线程 , 处理请求和结果
  • 流程
    1. 异步场景以线程(T1)中正常的请求处理开始
    2. 并发请求处理可以通过调用startCallableProcessing或startDeferredResultProcessing来启动,这两种方法都会在单独的线程(T2)中产生一个结果。
    3. 保存结果并将请求分发给容器,以便在第三个线程(T3)中继续处理保存的结果。
    4. 在已分派线程(T3)中,可以通过getConcurrentResult()访问保存的结果,或者通过hasConcurrentResult()检测其是否存在。

PS:M51_02_02 : checkMultipart 的目的

为什么这里需要校验一下 checkMultipart ? 其底层主要做了如下几件事 :

  • 判断是否有 multipartResolver 并且用该解析器判断是否为Multipart
  • 如果以上条件达成 , multipartResolver.resolveMultipart(request) 进行解析返回新 Request
  • 否则返回原有 request

说白了 , 就是 multipart request 的处理 , 但是相对的问题又来了 >>> 什么是 multipart request ?

作用 : HTTP 多部分请求是 HTTP 客户机构造的 HTTP 请求,用于将文件和数据发送到 HTTP 服务器。 
场景 : 浏览器和 HTTP 客户端通常使用它将文件上传到服务器。


PS:M51_02_04 getHandler 和 getHandlerAdapter 的区别 ?

getHandler -> HandlerExecutionChain
getHandlerAdapter -> HandlerAdapter

// HandlerExecutionChain 的作用 :
- HandlerExecutionChain 是 Handler 的处理器链 , 其中包含了 HandlerInterceptor 的数组和对应的 Handler 

// HandlerAdapter 的作用 :
- 首先 , 看名字就知道 , 这是个适配器 , 适配器能在原有功能上扩展新的功能
- MVC框架SPI,允许参数化核心MVC工作流 , 该接口用于允许DispatcherServlet无限扩展。
- DispatcherServlet通过这个接口访问所有已安装的处理程序
HandlerAdapter_system.png

PS:M51_02_05 GET/HEAD 请求细说

这地方老有意思了 ,刚接触代码那会这里出问题想了好久才知道有这么个东西

参考文档 @ www.cnblogs.com/longyongzhe…

特点 : HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。
作用 :

  1. 只请求资源的首部;
  2. 检查超链接的有效性;
  3. 检查网页是否被修改;
  4. 多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等

PS:M51_02_09 前置处理和后置处理主要处理什么 ?

- mappedHandler.applyPreHandle : 前置处理
- mappedHandler.applyPostHandle : 后置处理 

// 这2个方法主要是对拦截器的处理 , 可以看到其中直接调用拦截器的方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            HandlerInterceptor interceptor = interceptors[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
    return true;
}

M51_02 : DispatcherServlet # doDispatch 源码


protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        // 准备异步处理管理器 WebAsyncManager
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                // 尝试解析 Multipart Request
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // 获取具体需要执行的 Handler
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 确定当前请求的处理程序适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // 处理 Get-Head 请求
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                // 拦截器前置处理
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 调用 HandlerAdapter 处理 请求
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                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);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            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.3.2 HandlerMapping 解析到方法

上文中已经获取到了 Adapter , 以下就是 Adapter 的详细处理

流程处理

流程处理分为2个部分 , 简单点说就是 :

  • getHandler 获取使用的 MethodHandler
  • getHandlerAdapter 获取适配处理器
  • 通过适配处理器处理 MethodHandler

一 : 获取处理的 Handler (getHandler)

DispatcherServlet # M51_03- getHandler 中可以看到 , 通过 HandlerExecutionChain # getHandler 获取 Handler 对象

C76- AbstractHandlerMapping 
    M76_01- HandlerExecutionChain getHandler(HttpServletRequest request) : 构建处理链
        - getHandlerInternal(request) 获取处理的 Handler -> M32_01
        - 通过 Handler 构建 HandlerExecutionChain TODO 
        - 跨域配置的处理 CorsConfiguration
    M76_02- getHandlerInternal
        - 调用 父类 -> M32_01

C32- AbstractHandlerMethodMapping
   M32_01- getHandlerInternal(HttpServletRequest request)
        - 先配置了一个读锁
        - 调用 lookupHandlerMethod -> M32_02
   M32_02- lookupHandlerMethod : 对请求做真正的处理 , 获取 HandlerMethod
        1- 构建 List<Match> 用于存放匹配结果
        - MappingRegistry 通过 lookupPath 获取对象 List<RequestMappingInfo>
               ?- 底层实际上是调用上文初始化使用的 urlLookup.get(urlPath)
        - 调用 addMatchingMappings  , 将匹配的 Match放入 1 步构建的 List 中
        - 返回处理的 Method
       

M32_02 lookupHandlerMethod 请求处理

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<>();
        // 从 MappingRegistry 中获取 Mapping List
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
        }
        // 如果匹配项不为空 
        if (!matches.isEmpty()) {
             // {POST /test/getBody}
            Match bestMatch = matches.get(0);
            // 进行匹配 , 获取对应的 HandlerMethod
            if (matches.size() > 1) {
                Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
                matches.sort(comparator);
                bestMatch = matches.get(0);
                if (CorsUtils.isPreFlightRequest(request)) {
                    return PREFLIGHT_AMBIGUOUS_MATCH;
                }
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException(
                            "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
                }
            }
            
            // request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath) -> PS:M32_02_01
            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
             
            handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }

// PS:M32_02_01
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

步骤二 : 使用获取的 Handler (HandlerAdapter.handle)

从步骤一中我们已经获取到了 HandleMethod , 后续就是相关的处理逻辑

  • DispatcherServlet # doDispatch : 请求入口
  • AbstractHandlerMethodAdapter # handle : RequestMappingAdapter 的父入口
  • RequestMappingHandlerAdapter # handleInternal :请求处理主流程
  • RequestMappingHandlerAdapter # invokeHandlerMethod
  • ServletInvocableHandlerMethod # invokeAndHandle
  • InvocableHandlerMethod # invokeForRequest
  • InvocableHandlerMethod # doInvoke
  • Method # invoke : Java 反射到方法

步骤2-1 : RequestMappingHandlerAdapter # handleInternal 处理

在该方法中 , 如果需要视图解析,则调用准备ModelAndView的RequestMapping处理程序方法

核心 : ModelAndView 的准备

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);
            
            // 扩展InvocableHandlerMethod,通过注册的HandlerMethodReturnValueHandler处理返回值
            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);
            
            // ModuleAndView 容器
            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();
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }

            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

ModelAndViewContainer 参数详情 :

image.png



        
// Web 模块最终步骤     
C- InvocableHandlerMethod 

        
// 代码最终步骤 : 调用 Method 的 invoke 方法 , 去完成具体的逻辑        
C39- Method 
    M39_01- invoke(Object obj, Object... args)
        ?- 通过此方法调用最后的代理类 . java 反射包中方法 ,省略

2.4 补充 : 属性的转换

属性转换的主要类是 RequestMappingHandlerAdapter , 其主要调用逻辑为 :

  • C90- RequestMappingHandlerAdapter # M90_1- invokeHandlerMethod
  • C91- ServletInvocableHandlerMethod # M91_1- invokeAndHandle
  • C92- InvocableHandlerMethod # M92_1- invokeForRequest : 对请求进行处理
  • C93- InvocableHandlerMethod # M93_1- getMethodArgumentValues : 获取参数
  • C94- HandlerMethodArgumentResolverComposite # M94_1- resolveArgument : 解析参数
  • C95- RequestResponseBodyMethodProcessor # M95_1- readWithMessageConverters : 转换参数
  • C96- AbstractMessageConverterMethodArgumentResolver # M96_1- readWithMessageConverters : 最终处理逻辑
C- RequestMappingHandlerAdapter
    M- invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod)
        - invocableMethod.invokeAndHandle(webRequest, mavContainer)

// Step 1 : 处理的入口
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
    
    //  将 Request 解析处理
    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);
    try {
        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception ex) {
        throw ex;
    }
}


// PS : invokeForRequest 中主要流程
C- InvocableHandlerMethod 
    M- invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs)    
        - getMethodArgumentValues(request, mavContainer, providedArgs)
            ?- 详见下文参数获取

Step 2 : 参数的获取

    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
            }
        
        // 构建一个 Object 数组用于存放 param
        Object[] args = new Object[parameters.length];
        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) {
                throw ex;
            }
        }
        return args;
}



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);
}

Step 3 : RequestResponseBodyMethodProcessor 解析 RequestBody

 
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

    parameter = parameter.nestedIfOptional();
    // 读取并且转换为相关对象
    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    String name = Conventions.getVariableNameForParameter(parameter);

    if (binderFactory != null) {
        WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
        if (arg != null) {
            validateIfApplicable(binder, parameter);
            if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
            }
        }
        if (mavContainer != null) {
            mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
        }
    }
    return adaptArgumentIfNecessary(arg, parameter);
}


// Step  : 转换操作入口
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
            Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

    HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
    ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);

    Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
    if (arg == null && checkRequired(parameter)) {
        throw new HttpMessageNotReadableException("Required request body is missing: " +
                    parameter.getExecutable().toGenericString(), inputMessage);
    }
    return arg;
}

Step end : 最终处理

最终处理中, 对 属性参数进行了最后的映射

PS: M96_1_01 继承体系

  • C- EmptyBodyCheckingHttpInputMessage
  • C- HttpInputMessage
  • C- HttpMessage

PS:M96_01_02 , 所有的 MessageConverter

  • ByteArrayHttpMessageConverter
  • StringHttpMessageConverter
  • ResourceHttpMessageConverter
  • ResourceRegionHttpMessageConverter
  • SourceHttpMessageConverter
  • AllEncompassingFormHttpMessageConverter
  • Jaxb2RootElementHttpMessageConverter
  • MappingJackson2HttpMessageConverter
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
            Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

    MediaType contentType;
    boolean noContentType = false;
    try {
         // 内容类型 : application/json;charset=UTF-8
        contentType = inputMessage.getHeaders().getContentType();
    } catch (InvalidMediaTypeException ex) {
        throw new HttpMediaTypeNotSupportedException(ex.getMessage());
    }
    if (contentType == null) {
        noContentType = true;
        contentType = MediaType.APPLICATION_OCTET_STREAM;
    }
    
    // Controller 类
    Class<?> contextClass = parameter.getContainingClass();
    // 实体类 class
    Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
    if (targetClass == null) {
        ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
        targetClass = (Class<T>) resolvableType.resolve();
    }
    
    // 获取请求类型
    HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
    Object body = NO_VALUE;

    EmptyBodyCheckingHttpInputMessage message;
    try {
        // PS: M96_1_01
        message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
    
     // 获取所有的 HttpMessageConverter -> PS:M96_01_02
    for (HttpMessageConverter<?> converter : this.messageConverters) {
        Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
        GenericHttpMessageConverter<?> genericConverter =
            (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
         // 此处主要是 MappingJackson2HttpMessageConverter
        if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
            (targetClass != null && converter.canRead(targetClass, contentType))) {
            if (message.hasBody()) {
                 // 转换核心流程 -> PS:M96_01_02
                 // 主要为 Header 
                HttpInputMessage msgToUse =
                    getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                    ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
                body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
            } else {
                body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
            }
                break;
        }
            }
    } catch (IOException ex) {
        throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
    }

    if (body == NO_VALUE) {
        if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||(noContentType && !message.hasBody())) {
            return null;
        }
        throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
    }

    MediaType selectedContentType = contentType;
    Object theBody = body;
    LogFormatUtils.traceDebug(logger, traceOn -> {
        String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
        return "Read "" + selectedContentType + "" to [" + formatted + "]";
    });

    return body;
}

PS:M96_01_02 参数详情

convert_body.jpg
convert_maptoUser.jpg

2.5 补充 : Response 的转换

属性的转换主要在 HandlerMethodReturnValueHandlerComposite 中进行 , 主要的逻辑为 :

  • C- InvocableHandlerMethod # invokeForRequest
  • C- ServletInvocableHandlerMethod # invokeAndHandle
  • C- HandlerMethodReturnValueHandlerComposite # handleReturnValue : 调用 Handler 处理
  • C- RequestResponseBodyMethodProcessor # handleReturnValue
// - C91- ServletInvocableHandlerMethod  # M91_1- invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

    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);
    try {
        // 此处进行 return 处理 : HandlerMethodReturnValueHandlerComposite
        this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception ex) {
        throw ex;
    }
}


// HandlerMethodReturnValueHandlerComposite  # handleReturnValue
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);
}

// RequestResponseBodyMethodProcessor
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
    ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
    throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    // 此处进行返回处理 , 本次先不深入 , 以后单独看看返回的处理
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

原创文章,作者:睿达君,如若转载,请注明出处:http://zrrd.net.cn/1209.html

发表回复

登录后才能评论
咨询电话
联系电话:0451-81320577

地址:哈尔滨市松北区中小企业总部基地13F

微信咨询
微信咨询
QQ咨询
分享本页
返回顶部