zoukankan      html  css  js  c++  java
  • 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);
            
        }



  • 相关阅读:
    (转)Windows平台 杀死端口号进程
    android 基础知识总结
    使用安卓手机来运行与调试Android应用程序的步骤
    (转)JavaScript的eval(“{JSON object string}”)问题
    (转)Android手机连接电脑详细图文教程
    Nginx配置中FastCGI的几个命令
    设置nginx的超时时间
    Nginx配置中FastCGI的几个命令
    启用django的gzip压缩支持
    启用django的gzip压缩支持
  • 原文地址:https://www.cnblogs.com/520playboy/p/8377383.html
Copyright © 2011-2022 走看看