美文网首页
SpringMVC流程分析(附源码)

SpringMVC流程分析(附源码)

作者: _麻辣香锅不要辣 | 来源:发表于2019-11-08 10:57 被阅读0次

    1.简介

    SpringMVC框架是以请求为驱动,围绕Servlet设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是DispatcherServlet,它是一个Servlet,顶层是实现的Servlet接口。


    结构图

    2.流程分析

    流程分析.png

    既然DispathcherServlet是一个Servlet,那么就有Servlet的基本的方法,1.首先进入的肯定是Service(),在FrameworkServlet类中被重写

    @Override
        protected void service(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
            if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
                processRequest(request, response);
            }
            else {
                super.service(request, response);
            }
        }
    

    2.进入Service()后,又调用super.service(),即HttpServlet类中的service()

    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    
            String method = req.getMethod();
    
            if (method.equals(METHOD_GET)) {
                long lastModified = getLastModified(req);
                if (lastModified == -1) {
                    // servlet doesn't support if-modified-since, no reason
                    // to go through further expensive logic
                    doGet(req, resp);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    } catch (IllegalArgumentException iae) {
                        // Invalid date header - proceed as if none was set
                        ifModifiedSince = -1;
                    }
                    if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                        // If the servlet mod time is later, call doGet()
                        // Round down to the nearest second for a proper compare
                        // A ifModifiedSince of -1 will always be less
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else {
                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                    }
                }
    
            } else if (method.equals(METHOD_HEAD)) {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);
    
            } else if (method.equals(METHOD_POST)) {
                doPost(req, resp);
    
            } else if (method.equals(METHOD_PUT)) {
                doPut(req, resp);
    
            } else if (method.equals(METHOD_DELETE)) {
                doDelete(req, resp);
    
            } else if (method.equals(METHOD_OPTIONS)) {
                doOptions(req,resp);
    
            } else if (method.equals(METHOD_TRACE)) {
                doTrace(req,resp);
    
            } else {
                //
                // Note that this means NO servlet supports whatever
                // method was requested, anywhere on this server.
                //
    
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);
    
                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
            }
        }
    

    3.之后就会根据请求方式调用doGet(),doPost()等,这几个方法都在FrameworkServlet类中被重写。

        @Override
        protected final void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            processRequest(request, response);
        }
    
        /**
         * Delegate POST requests to {@link #processRequest}.
         * @see #doService
         */
        @Override
        protected final void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            processRequest(request, response);
        }
    

    4.看源码可知,doGet()、doPost()等方法内部都调用的是processRequest(request, response)这个方法

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            long startTime = System.currentTimeMillis();
            Throwable failureCause = null;
    
            LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
            LocaleContext localeContext = buildLocaleContext(request);
    
            RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    
            initContextHolders(request, localeContext, requestAttributes);
    
            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 {
                resetContextHolders(request, previousLocaleContext, previousAttributes);
                if (requestAttributes != null) {
                    requestAttributes.requestCompleted();
                }
    
                if (logger.isDebugEnabled()) {
                    if (failureCause != null) {
                        this.logger.debug("Could not complete request", failureCause);
                    }
                    else {
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            logger.debug("Leaving response open for concurrent processing");
                        }
                        else {
                            this.logger.debug("Successfully completed request");
                        }
                    }
                }
    
                publishRequestHandledEvent(request, response, startTime, failureCause);
            }
        }
    

    5.然后调用的是doService(request, response);这是个定义在FrameworkServlet中的一个抽象方法,在DispatcherServlet类实现

    protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
                throws Exception;
    
    @Override
        protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (logger.isDebugEnabled()) {
                String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
                logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                        " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
            }
    
            // Keep a snapshot of the request attributes in case of an include,
            // to be able to restore the original attributes after the include.
            Map<String, Object> attributesSnapshot = null;
            if (WebUtils.isIncludeRequest(request)) {
                attributesSnapshot = new HashMap<>();
                Enumeration<?> attrNames = request.getAttributeNames();
                while (attrNames.hasMoreElements()) {
                    String attrName = (String) attrNames.nextElement();
                    if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                        attributesSnapshot.put(attrName, request.getAttribute(attrName));
                    }
                }
            }
    
            // Make framework objects available to handlers and view objects.
            request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
            request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
            request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
            request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    
            if (this.flashMapManager != null) {
                FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
                if (inputFlashMap != null) {
                    request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
                }
                request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
                request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
            }
    
            try {
                doDispatch(request, response);
            }
            finally {
                if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                    // Restore the original attribute snapshot, in case of an include.
                    if (attributesSnapshot != null) {
                        restoreAttributesAfterInclude(request, attributesSnapshot);
                    }
                }
            }
        }
    

    6.然后调用doDispatch(request, response),这是最核心的一个方法

    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);
                    multipartRequestParsed = (processedRequest != request);
    
                    // Determine handler for the current request.
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    // Determine handler adapter for the current request.
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    // Process last-modified header, if supported by the handler.
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if (logger.isDebugEnabled()) {
                            logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                        }
                        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }
    
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
    
                    // Actually invoke the handler.
                    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);
                    }
                }
            }
        }
    
    • mappedHandler = getHandler(processedRequest);根据请求获取handler(可以理解为controller)
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            if (this.handlerMappings != null) {
                for (HandlerMapping hm : this.handlerMappings) {
                    if (logger.isTraceEnabled()) {
                        logger.trace(
                                "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
                    }
                    HandlerExecutionChain handler = hm.getHandler(request);
                    if (handler != null) {
                        return handler;
                    }
                }
            }
            return null;
        }
    

    这里的handlerMappings是在一开始的时候初始化好的,可以看下springMVC初始化流程
    handlerMappings里面有requestMapping和与之对应的方法名

    debug1.png
    debug2.png
    自己定义的一个Controller
    @Controller
    public class FirstController {
        @RequestMapping("/test")
        public Object first(){
            return "111";
        }
        @RequestMapping("test1")
        public Object second(){
            return "222";
        }
    }
    

    最后返回一个handler


    image.png
    • HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()),根据获取的handler,获取特定的handlerAdapter,handlerAdapter来处理业务逻辑
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            if (this.handlerAdapters != null) {
                for (HandlerAdapter ha : this.handlerAdapters) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Testing handler adapter [" + ha + "]");
                    }
                    if (ha.supports(handler)) {
                        return ha;
                    }
                }
            }
    
    • mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
      最后调用
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
    

    接着一步步的调试,运用反射调用controller中对应的方法。

    相关文章

      网友评论

          本文标题:SpringMVC流程分析(附源码)

          本文链接:https://www.haomeiwen.com/subject/yufulctx.html