美文网首页
springmvc处理请求源码

springmvc处理请求源码

作者: sunpy | 来源:发表于2020-09-11 14:03 被阅读0次
    springmvc处理请求.jpg

    1. FrameworkServlet抽象类设计

    DispatcherServlet继承抽象类FrameworkServlet,最终父类为HttpServlet,本质上还是Servlet来处理请求。


    代码结构设计思路:实现处理请求的doGet方法,其中doGet方法共性的流程都是doGet方法委派给processRequest方法,processRequest方法委派给doService方法。而doService是抽象方法,由继承FrameworkServlet的个性子类来实现doService的个性化内容方法(模板方法模式)。

        // 处理请求,将请求委派给processRequest和doService
        @Override
        protected final void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            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 ex) {
                failureCause = ex;
                throw ex;
            }
            catch (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, startTime, failureCause);
            }
        }
    

    2.DispatcherServlet处理请求入口(doService方法)

    如果后面需要处理国际化和一些主题样式等,先在向后传的reuqest请求中,设置themeResolver主题样式解析器和localeResolver国际化解析器等属性。主要还是将请求委派到doDispatch方法去实现。

    // 确定请求request的一些属性并且委派给doDispatch方法处理请求
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            String requestUri = urlPathHelper.getRequestUri(request);
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                    " processing " + request.getMethod() + " request for [" + requestUri + "]");
        }
    
        // 保留请求属性的快照,将当前的属性遍历保存到attributesSnapshot
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            logger.debug("Taking snapshot of request attributes before include");
            attributesSnapshot = new HashMap<String, Object>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }
    
        // 确保框架对象对于处理器和视图对象可用
        // 请求中保存一些主题属性和国际化解析器属性等
        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());
    
        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()) {
                return;
            }
    
            // 还原请求的属性快照
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
    

    3. doDispatch方法核心处理:处理请求,派发到不同的handler处理器

    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.
                // 1 根据请求获取对应处理器映射HandlerMapping
                // 返回执行链
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                // 2 获取处理器适配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                // 3 请求是否发生修改,未修改采取本地缓存
                
                // 获取请求方法
                String method = request.getMethod();
                // 判断请求是否为GET请求
                boolean isGet = "GET".equals(method); 
                if (isGet || "HEAD".equals(method)) {
                    // 获取最后修改时间
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    // 如果请求没有修改,那么通知其使用本地缓存
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
    
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
    
                try {
                    // 4 真正调用处理请求程序,返回ModelAndView
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
                
                // 重置为默认的视图名称
                applyDefaultViewName(request, mv);
                // 调用已注册拦截器的方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            // 5 ViewResolver解析视图
            // 调用render方法渲染物理视图View
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
    

    说明,粗略地分为5个步骤:
    ① 根据请求获取对应处理器映射HandlerMapping,返回执行链
    ② 获取处理器适配器
    ③ 请求是否发生修改,未修改直接返回,采取本地缓存
    ④ 真正调用处理请求程序,返回ModelAndView
    ⑤ ViewResolver解析视图,渲染物理视图View


    • ① 根据请求获取对应处理器映射HandlerMapping,返回执行链(getHandler方法)



      RequestMappingHandlerMapping类继承自祖先AbstractHandlerMapping抽象类,由祖先抽象类实现getHandler方法。

    // 获取请求对应的HandlerExecutionChain
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            // 获取请求对应的HandlerExecutionChain处理器执行链
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
    
    // 获取请求对应的HandlerExecutionChain处理器执行链
    // 如果不存在,那么返回特定的处理器执行链
    @Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 根据请求获取处理器执行链
        Object handler = getHandlerInternal(request);
        // 获取默认的处理器
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        // 封装处理器为处理器执行链并返回
        return getHandlerExecutionChain(handler, request);
    }
    
    • ② getHandlerAdapter方法:获取处理器适配器


    // 获取handler处理器对应的HandlerAdapter适配器
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            // 判断HandlerAdapter是否支持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");
    }
    
    • ③ 请求是否发生修改,未修改直接返回,采取本地缓存
      通过ETAG和lastmodifiedtime来确定是否修改了请求资源,如果未修改就返回304状态码。
      使用本地缓存的原理(看完就比较清楚为啥这么写了):https://www.jianshu.com/p/699d845a2a73
    String method = request.getMethod();
    boolean isGet = "GET".equals(method); 
    if (isGet || "HEAD".equals(method)) {
        // 获取最后修改时间
        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
        if (logger.isDebugEnabled()) {
            String requestUri = urlPathHelper.getRequestUri(request);
            logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
        }
        // 如果请求没有修改,那么通知其使用本地缓存
        if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
            return;
        }
    }
    
    // 检查是否修改过请求,通过ETAG确定资源,lastmodifiedtime来确定修改时间
    @Override
    public boolean checkNotModified(long lastModifiedTimestamp) {
        if (lastModifiedTimestamp >= 0 && !this.notModified &&
                (this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
            long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
            this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
            if (this.response != null) {
                if (this.notModified && METHOD_GET.equals(getRequest().getMethod())) {
                    this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
                else {
                    this.response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
                }
            }
        }
        return this.notModified;
    }
    
    • ④ 真正调用处理请求程序,返回ModelAndView
      执行handle方法的类为RequestMappingHandlerAdapter,继承自AbstractHandlerMethodAdapter抽象类,父类定义的handle方法,将具体实现下沉到RequestMappingHandlerAdapter的handleInternal方法。
    @Override
    protected final ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        
        // 检查支持的方法和所需的会话,并应用给定的缓存秒数
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            
            checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
        }
        else {
            // Uses configured default cacheSeconds setting.
            checkAndPrepare(request, response, true);
        }
    
        // Session互斥锁
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    return invokeHandleMethod(request, response, handlerMethod);
                }
            }
        }
    
        // 为视图解析做准备
        return invokeHandleMethod(request, response, handlerMethod);
    }
    

    通过反射的方式调用请求的方法,譬如我们Controller定义的方法

    // 在给定请求的上下文中解析其参数值后调用该方法。
    public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        // 获取当前请求方法的参数
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            StringBuilder sb = new StringBuilder("Invoking [");
            sb.append(this.getBeanType().getSimpleName()).append(".");
            sb.append(getMethod().getName()).append("] method with arguments ");
            sb.append(Arrays.asList(args));
            logger.trace(sb.toString());
        }
        // 反射方式,使用参数调用给定的方法
        Object returnValue = invoke(args);
        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
        }
        return returnValue;
    }
    
    • ⑤ viewResolver解析视图,将model填充到view
    // 渲染视图
    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    
        boolean errorView = false;
    
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }
    
        // Did the handler return a view to render?
        if (mv != null && !mv.wasCleared()) {
            // 渲染视图
            render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                        "': assuming HandlerAdapter completed request handling");
            }
        }
    
        if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Concurrent handling started during a forward
            return;
        }
    
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }
    
    // 渲染ModelAndView
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 解析请求中的国际化
        Locale locale = this.localeResolver.resolveLocale(request);
        // 设置到响应中
        response.setLocale(locale);
    
        View view;
        if (mv.isReference()) {
            // 解析视图名称
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException(
                        "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
                                getServletName() + "'");
            }
        }
        else {
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name '" + getServletName() + "'");
            }
        }
    
        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        try {
            // 将model填充到view即可
            view.render(mv.getModelInternal(), request, response);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '"
                        + getServletName() + "'", ex);
            }
            throw ex;
        }
    }
    
    // 遍历视图解析器,将视图解析为物理视图
    protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
            HttpServletRequest request) throws Exception {
    
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
        return null;
    }
    

    相关文章

      网友评论

          本文标题:springmvc处理请求源码

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