SpringMVC解析4-DispatcherServlet逻辑脉络

简介: HttpServlet提供了不同的服务方法,它们是doDelete(),doGet(),doOptions(),doPost(),doPut(),和doTrace(),它会根据不同的请求形式将程序引导至对应的函数进行处理。

HttpServlet提供了不同的服务方法,它们是doDelete(),doGet(),doOptions(),doPost(),doPut(),和doTrace(),它会根据不同的请求形式将程序引导至对应的函数进行处理。这几个函数中最常用的函数无非就是doGet()和doPost(),我们看看DispatcherServlet对着两个函数的逻辑实现。

@Override  
protected final void doGet(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
  
    processRequest(request, response);  
}  
@Override  
protected final void doPost(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
  
    processRequest(request, response);  
}  
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)  
        throws ServletException, IOException {  
    //记录当前时间,用于计算web请求的处理时间  
    long startTime = System.currentTimeMillis();  
    Throwable failureCause = null;  
    //根据当前request创建对应的LocaleContext和RequestAttributes,并绑定到当前线程  
    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方法进一步处理  
        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);  
    }  
}  

函数中已经开始了对请求的处理,虽然把细节转移到了doService函数中实现,但也看得出处理请求前后所做的准备工作。

(1)为了保证当前线程的LocaleContext以及RequestAttributes可以在当前请求后还能恢复,提取当前线程的两个属性。

(2)根据当前request创建对应的LocaleContext和RequestAttributes,并绑定到当前线程。

(3)委托给doService方法进一步处理。

(4)请求处理结束后恢复线程到原始状态。

(5)请求处理结束后无论成功与否发布事件通知

继续查看doService方法。

@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<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));  
            }  
        }  
    }  
  
    // 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());  
  
    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);  
            }  
        }  
    }  
}  

我们猜想对请求处理至少应该包括一些诸如寻找handler并页面跳转之类的逻辑处理,但是,在doService中我们并没有看到想看到的逻辑,相反却同样是一些准备工作,但是这些准备工作是必不可少的。Spring将已经初始化的功能辅助工具变量,比如localeResolver,themeResolver等设置在request属性中,而这些属性会在接下来派上用场。doDispatch函数中展示了Spring请求处理所涉及的主要逻辑,而我们之前设置在request中的各种辅助属性也都有被派上了用场。

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 {  
            //如果是MultipartContent类型的request则转换request为MultipartHttpServletRequest类型的request  
            processedRequest = checkMultipart(request);  
            multipartRequestParsed = (processedRequest != request);  
  
            // Determine handler for the current request.  
            //根据request信息寻找对应的handler  
            mappedHandler = getHandler(processedRequest, false);  
            if (mappedHandler == null || mappedHandler.getHandler() == null) {  
                //如果没有找到对应的handler则通过response反馈错误信息  
                noHandlerFound(processedRequest, response);  
                return;  
            }  
  
            // Determine handler adapter for the current request.  
            //根据当前的handler寻找对应的handlerAdapter  
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
  
            // Process last-modified header, if supported by the handler.  
            String method = request.getMethod();  
            //如果handler支持last-modified头处理  
            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;  
                }  
            }  
            //拦截器的preHandler方法的调用  
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {  
                return;  
            }  
            // Actually invoke the handler.  
            //真正的激活handler并返回视图  
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
  
            if (asyncManager.isConcurrentHandlingStarted()) {  
                return;  
            }  
            //视图名称转换应用于需要添加前缀后缀的情况  
            applyDefaultViewName(request, mv);  
            //调用所有拦截器的postHandle方法  
            mappedHandler.applyPostHandle(processedRequest, response, mv);  
        }  
        catch (Exception ex) {  
            dispatchException = ex;  
        }  
        //页面处理  
        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  
            if (mappedHandler != null) {  
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);  
            }  
        }  
        else {  
            // Clean up any resources used by a multipart request.  
            if (multipartRequestParsed) {  
                cleanupMultipart(processedRequest);  
            }  
        }  
    }  
}  
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);  
    }  
}  

Spring每一步是怎么处理dispatcher中的方法的,在下面一节分析。

 

目录
相关文章
|
22天前
|
XML 存储 Java
Spring重要类解析
Spring重要类解析
19 0
|
2月前
|
XML Java 数据格式
Spring 应用上下文探秘:生命周期解析与最佳实践
Spring 应用上下文探秘:生命周期解析与最佳实践
73 0
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
2月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
34 1
|
20天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
43 1
|
1月前
|
XML Java 开发者
深入解析 Spring 和 Spring Boot 的区别
深入解析 Spring 和 Spring Boot 的区别
|
6天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
14 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
6天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
22 2
从入门到精通:Spring基础注解的全面解析
|
6天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
19 0
切面编程的艺术:Spring动态代理解析与实战
|
6天前
|
Java 关系型数据库 MySQL
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
20 0
高级对象装配:解析Spring创建复杂对象的秘诀

推荐镜像

更多