spring mvc之请求过程源码分析

简介

上一篇,我们分析了spring mvc启动过程的源码,这一节,来一起分析下在用户请求controller的过程中,spring mvc做了什么事?

一、准备

我写这么一个controller

package com.jacky.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;

@Controller
    @RequestMapping("/bbb")
    public class IndexController {

        @RequestMapping(value = "/test.do", method = RequestMethod.GET)
        public String index() {
            return "index";
        }

        @RequestMapping(value = "/aaa.do", method = RequestMethod.GET)
        @ResponseBody
        public String aaa() {
            return "aaa";
        }


    }

 

二、用户请求controller的过程(http://localhost:8080/spring-mvc-demo/bbb/aaa.do)

上一篇,我们知道了,spring mcv基于servlet的,核心类是DispatcherServlet,那根据Servlet的知识,请求首先service()方法,但是在DispatherServlet中并没有找到service方法,在其父类FrameworkServlet中找到service方法,那我们就从这里看起。

 protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
            processRequest(request, response);
        }
        else {
            super.service(request, response);
        }
    }

2.1、接下来我们看处理请求方法processRequest(request, response)

 protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            doService(request, response);
        }

2.2、接下来我们看看doService(request,response)方法

 protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        doDispatch(request, response);
    }

2.3、接下来我们看看DispatcherServlet的doDispatch(request,reponse)方法

 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        ModelAndView mv = null;
        Exception dispatchException = null;
        processedRequest = checkMultipart(request);
        multipartRequestParsed = (processedRequest != request);

        //根据请求获得请求执行链
        mappedHandler = getHandler(processedRequest);
        //根据处理器获得对应的适配器
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
        //调用controller中的method的方法之前先调用拦截器的preHandle方法
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
        }

        //根据请求调用controller中的method,然后返回ModelAndView
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        //调用spring mvc拦截器的postHandle方法
        mappedHandler.applyPostHandle(processedRequest, response, mv);
    }

这个方法里面有很多很关键的方法,没事我们一个个看里面的实现细节

2.4、首先我们看看获得请求执行链的方法getHandler(processedRequest)

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //遍历spring mvc启动时初始化好的handlerMappings(类型为List<HandlerMapping>)
        for (HandlerMapping hm : this.handlerMappings) {
            //利用handlerMaping取得处理器执行链
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

2.5、接下来我们看看handlerMaping是怎么取得处理器执行链的?

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获得HandlerMethod对象
        Object handler = getHandlerInternal(request);
        //获得处理器执行链对象
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        return executionChain;
    }

2.6、首先我来看看怎么获得HandleMethod对象的

    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获得请求路径,这里是lookupPath="/bbb/aaa.do"
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        //开启读锁
        this.mappingRegistry.acquireReadLock();
        try {
            //根据url获得HandleMethod
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
        }
        finally {
            //释放读锁
            this.mappingRegistry.releaseReadLock();
        }
    }

2.7、接下来我们看看getHandlerExecutionChain是怎么获得处理器执行链的

 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
            if (interceptor instanceof MappedInterceptor) {
                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                    //往处理器执行链的List<HandlerInterceptor>类型的interceptorList集合中,存放拦截器
                    chain.addInterceptor(mappedInterceptor.getInterceptor());
                }
            }
            else {
                chain.addInterceptor(interceptor);
            }
        }
        return chain;
    }

从这里我们可以看到处理器其实封装了拦截器集合和一个handleMethod对象(封装了controller Class对象,浏览器请求的Controler中的method方法对象,参数)

2.8、上面,我们知道了,springMVC是怎么通过handleMaping获得handle(HandleMethod)对象,以及怎么添加拦截器,组装成处理器执行链,接下来我们继续看看springMVC是怎么获得处理器对应的

适配器的。

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        //遍历spring mvc初始化时,设置的DispatcherServlet的成员变量List<HandlerAdapter> handlerAdapters
        for (HandlerAdapter ha : this.handlerAdapters) {
//判断适配器支不支持handler
if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }

因为有会遍历很多种适配器,从上面我们知道,handlerd的类型是HandleMethod,所以的我们看的是RequestMappingHandlerAdapter适配器,根据RequestMappingHandlerAdapter的继承关系

可以知道,RequestMappingHandlerAdapter继承了AbstractHandlerMethodAdapter,在ha.supports(handler)方法中,刚好在AbstractHandlerMethodAdapter类中,我们来看看

public final boolean supports(Object handler) {
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

 就是判断传入的handler是否是属于HandlerMethod类型的,如果是,就返回true,然后RequestMappingHandlerAdapter对象

2.9、springMVC怎么获得处理请求的适配器我们看完了,接下来,我们看看,获得适配器后,是怎么调用到controller中的对应的method的?

 //根据请求调用controller中的method,然后返回ModelAndView
 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
首先调用的是AbstractHandlerMethodAdapter类的handle方法
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return handleInternal(request, response, (HandlerMethod) handler);
    }

可以看到这个方法没干什么,只是调用了handleInternal方法,那我们就看看这个方法

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

这个方法主要是调了invokeHandlerMethod方法,那我们继续来看卡这个方法干了什么?

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

            //把handlerMethod封装成ServletInvocableHandlerMethod
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            //设置参数解析器
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            //设置spring mvc请求controller的method返回值处理器
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            invocableMethod.setDataBinderFactory(binderFactory);
            //设置参数名称发现器
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

3.0、接下来我们看看真正的调用和处理方法invocableMethod.invokeAndHandle(webRequest, mavContainer);

public void invokeAndHandle(ServletWebRequest webRequest,
                                ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        //在这里通过反射调用controller中的method方法
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);

        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        } else if (StringUtils.hasText(this.responseReason)) {
            mavContainer.setRequestHandled(true);
            return;
        }

        mavContainer.setRequestHandled(false);
        //在这里通过返回值处理器处理器进行二次处理,例如:如果加了方法加了reponseBody注解,就把结果序列化json字符串再返回
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        
    }

 




posted @ 2018-01-29 15:04  坏~牧羊人  阅读(444)  评论(0编辑  收藏  举报