北冰洋以北 发表于 2024-8-2 09:55:34

SpringMVC源码剖析(二):哀求执行流程

SpringMVC源码系列文章
SpringMVC源码剖析(一):web容器启动流程
SpringMVC源码剖析(二):哀求执行流程


前言

  前文中我们介绍了SpringMVC容器的启动,包括前端控制器DispatcherServlet对象的创建,过滤器添加到Tomcat容器的过滤器集合中,将全部拦截器、跨域设置、消息转换器等设置统一添加到各自集合中,剖析@RequestMapping注解生成哀求路径和Controller方法的映射map。本章来研究下哀求的执行过程。
  说到哀求过程,那么得先说下入口在哪里?入口肯定是统一分发哀求给处置惩罚程序的DispatcherServlet,DispatcherServlet归根结底也是Servlet。Tomcat通过哀求Mapping映射和Servelt对应关系找到Servelt,调用Servelt之前会执行过滤器链,全部过滤器放行才会走到Servelt真正的执行逻辑。


[*]依照常见的post哀求为例
// 接受User对象并返回
@PostMapping("/test")
@ResponseBody
public User test(@RequestBody User user) {
    user.setName("李四");
    System.out.println(user);
    return user;
}


[*]方法栈调用链
https://i-blog.csdnimg.cn/direct/304096b704944651bab7fb24bcbd2021.png


[*]HttpServelt#service分水岭doPost方法,只要找到DispatcherServelt重写的doPost方法就是入口了
https://i-blog.csdnimg.cn/direct/f5a7e1a7d2484e779ff663c0ce20a2f3.png
  本文就不讲过滤器的调用了,因为从DispatcherServelt开始,过滤器链已经执行完成,之前文章Tomcat源码剖析(八):一个哀求的执行流程(附Tomcat整体总结)有介绍过。
DispatcherServlet入口

DispatcherServlet的类图如下:
https://i-blog.csdnimg.cn/direct/67ab878324364126b7884f4c65868596.png
   从doPost到doDispatch方法


[*]doPost方法是由DispatcherServelt的父类FrameworkServlet实现的
[*]岂论post还是get哀求都是调用同一个方法processRequest(request, response)
[*]对于方法参数request和respons都是Tomcat容器创建的,以前文章Tomcat源码剖析(七):底层怎样获取哀求url、哀求头、json数据?有详细介绍
https://i-blog.csdnimg.cn/direct/a6c5a3ee3a064ff0b9fe60eff239f4d1.png


[*]主要方法doService(request, response)
// FrameworkServlet类方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {

        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;

        ...

        try {
                doService(request, response);
        }
        catch (ServletException | IOException ex) {
                failureCause = ex;
                throw ex;
        }
        catch (Throwable ex) {
                failureCause = ex;
                throw new NestedServletException("Request processing failed", ex);
        }

        finally {
                ...
        }
}


[*]主要方法doDispatch(request, response)
// DispatcherServlet类方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // ... 设置一堆Attribute属性

        try {
                doDispatch(request, response);
        }
        finally {
                ...
        }
}
   核心方法doDispatch


[*]这个方法包含了SpringMVC的整个执行流程
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
       
        // 异步请求相关,以后单独篇章讲
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

                try {
                        // 判断是否上传请求,以后有机会单独将
                        processedRequest = checkMultipart(request);
                        // 如果是上传请求,这个参数置为true,最后会去清理资源
                        multipartRequestParsed = (processedRequest != request);

                        // 获取HandlerExcutionChain (内部包括Handler)
                        mappedHandler = getHandler(processedRequest);
                        if (mappedHandler == null) {
                                // 请求url找不到404就会走到这里
                                noHandlerFound(processedRequest, response);
                                return;
                        }

                        // 获取适配器
                        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                        // get请求缓存相关,以后有机会单独将
                        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;
                                }
                        }
                       
                        // 调用拦截器的前置方法preHandle
                        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                                return;
                        }

                        // 执行handler方法
                        // 需要跳转页面这里才会返回ModelAndView对象,否则@ResponseBody返回对象这里返回null
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

                        applyDefaultViewName(processedRequest, mv);
                        // 调用拦截器的后置方法postHandle
                        mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                        dispatchException = ex;
                }
                catch (Throwable err) {
                        //从4.3开始,我们也在处理处理程序方法抛出的错误,
                        //使它们可用于@ExceptionHandler方法和其他场景。
                        dispatchException = new NestedServletException("Handler dispatch failed", err);
                }
                // 处理结果
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
                // 调用拦截器请求处理完成后的回调triggerAfterCompletion
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
                // 调用拦截器请求处理完成后的回调triggerAfterCompletion
                triggerAfterCompletion(processedRequest, response, mappedHandler,
                                new NestedServletException("Handler processing failed", err));
        }
        finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                        // 异步处理的回调
                        if (mappedHandler != null) {
                                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                        }
                }
                else {
                        // 如果是上传请求,清理相关资源
                        if (multipartRequestParsed) {
                                cleanupMultipart(processedRequest);
                        }
                }
        }
}
一、获取HandlerExcutionChain(包括Handler)

  遍历全部的HandlerMapping,只要getHandler方法能获取到HandlerExecutionChain立即返回。
// DispatcherServlet类方法
@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;
}
  如下这三个HandlerMapping是web容器启动时候加载的,上篇文章SpringMVC源码剖析(一):web容器启动流程有详细介绍。三个轮番调用getHandler方法,而HandlerMapping也有次序的,RequestMappingHanderMapping排序为0优先级最高,而它也是处置惩罚@RequestMapping注解的映射关系的映射器。
https://i-blog.csdnimg.cn/direct/80eef563fcbd40d78dc19711234ff198.png
  调用抽象类的方法,那么上面看到的三个HandlerMapping应该都会调用此方法,而这里肯定有一些核心的不同的方法实现在不同的HandlerMapping详细实现类中,典型的模板方法计划模式。
// AbstractHandlerMapping类方法
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 获取Handler
        Object handler = getHandlerInternal(request);
        if (handler == null) {
                handler = getDefaultHandler();
        }
        if (handler == null) {
                return null;
        }
        // handler为bean的名称
        // 这种Controller应该是实现Controler、HttpRequestHandler接口的方式
        // 以前的老实现方式,暂不研究
        if (handler instanceof String) {
                String handlerName = (String) handler;
                handler = obtainApplicationContext().getBean(handlerName);
        }
       
        ...
       
        // 获取执行链(包括Handler和拦截器)
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

        // ...打印日志
       
        // 添加跨域设置(本身也是拦截器)到拦截器链中第一个位置
        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;
}
1、获取Handler



[*]主要内容就是调用父类AbstractHandlerMethodMapping的雷同方法
// RequestMappingInfoHandlerMapping类方法
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        try {
                // 核心方法调用父类的getHandlerInternal方法
                return super.getHandlerInternal(request);
        }
        finally {
                ProducesRequestCondition.clearMediaTypesAttribute(request);
        }
}


[*]通过request获取查找路径
[*]通过查找路径获取HandlerMethod
// AbstractHandlerMethodMapping类方法
@Override
@Nullable
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        // 通过request获取查找路径
        String lookupPath = initLookupPath(request);
        this.mappingRegistry.acquireReadLock();
        try {
                // 通过查找路径获取HandlerMethod
                HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
                return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
                this.mappingRegistry.releaseReadLock();
        }
}
1.1、通过request获取查找路径



[*]截取哀求uri,如图/springmvc/test,/springmvc为项目路径,/test为我们需要的查找路径
https://i-blog.csdnimg.cn/direct/5b9e68a3f1e54aeebbfd91ba58fe50f0.png
1.2、通过查找路径获取HandlerMethod

  这个方法的核心内容就是从之前讲的SpringMVC源码剖析(一):web容器启动流程注册的两个map获取数据。
https://i-blog.csdnimg.cn/direct/4605bb00107c42e0897fc71497456418.png
// AbstractHandlerMethodMapping类方法
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<>();
        // 通过查找路径获取RequestMappingInfo
        List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
        if (directPathMatches != null) {
                // 通过RequestMappingInfo获取HandlerMethod
                addMatchingMappings(directPathMatches, matches, request);
        }
        ...
        if (!matches.isEmpty()) {
                Match bestMatch = matches.get(0);
                if (matches.size() > 1) {
                        //...匹配多个,抛错异常
                }
                request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
                handleMatch(bestMatch.mapping, lookupPath, request);
                // 获取HandlerMethod并返回
                return bestMatch.getHandlerMethod();
        }
        else {
                return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
        }
}
https://i-blog.csdnimg.cn/direct/c408fa733770427480fd76b0436232a2.png
2、获取执行链(包括Handler、拦截器)

  我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层,为了统一调用matcher方法,匹配此拦截器哀求是否拦截本次哀求,如果是则会添加到拦截器链中。
// AbstractHandlerMapping类方法
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        // 创建HandlerExecutionChain对象
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                        (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
       
        // 遍历所有的拦截器,这拦截器是web容器启动时候解析加载的的
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
                // 我们自定义的拦截器统一用MappedInterceptor这个拦截器包装了一层
                // 为了统一的匹配方法,下面调用maches
                if (interceptor instanceof MappedInterceptor) {
                        MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                        // matcher匹配当前请求路径是否符合拦截器的拦截请求
                        if (mappedInterceptor.matches(request)) {
                                chain.addInterceptor(mappedInterceptor.getInterceptor());
                        }
                }
                else {
                        chain.addInterceptor(interceptor);
                }
        }
        return chain;
}

// 执行器链对象,主要就是两个属性handler:Handler对象,interceptorList:拦截器集合
public class HandlerExecutionChain {
        private final Object handler;
        private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
        // 构造方法
        public HandlerExecutionChain(Object handler) {
                this(handler, (HandlerInterceptor[]) null);
        }
        ...
}


[*]拦截器链终极的结果
https://i-blog.csdnimg.cn/direct/bd3282c1381e4e12a6c6ff068c300ea6.png
二、获取适配器

   看下HandlerAdapter接口
public interface HandlerAdapter {

        /**
       * 因为有多个HandlerMapping和HandlerAdapter
       * 对于HandlerAdapter是否支持对应的HandlerMapping,通过此方法判断
       */
        boolean supports(Object handler);

        /**
       * 具体调用Hangder的方法
       */
        @Nullable
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
  因为不同的Hander(@RequestMapping、实现Controller接口、实现HttpRequestHandler接口)对应的HandlerAdapter(适配器)不一样,通过HandlerAdapter的supports方法判断当前HandlerAdapter是否支持此次哀求的Hander。
// DispatcherServlet类方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
                for (HandlerAdapter adapter : this.handlerAdapters) {
                        if (adapter.supports(handler)) {
                                return adapter;
                        }
                }
        }
        throw new ServletException("No adapter for handler [" + handler +
                        "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}


[*]这个是抽象类实现的supports方法,全部HandlerAdapter判断是否支持都会走这里
[*]其主要作用就是supportsInternal方法,在不同的HandlerAdapter实现类中重写

[*]RequestMappingHandlerAdapter重写的supportsInternal返回true,表示其支持

// AbstractHandlerMethodAdapter类方法
@Override
public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

// RequestMappingHandlerAdapter类方法
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
}
  由上面HandlerAdapter接口可以猜到,RequestMappingHandlerAdapter适配器就是我们需要的,之后会通过handle方法去执行Hangder方法即调用Controller#Method。
三、执行Handler(
页: [1]
查看完整版本: SpringMVC源码剖析(二):哀求执行流程