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中的方法的,在下面一节分析。

 

目录
相关文章
|
6月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
1343 1
|
7月前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
10月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
248 2
|
8月前
|
XML Java 开发者
Spring底层架构核心概念解析
理解 Spring 框架的核心概念对于开发和维护 Spring 应用程序至关重要。IOC 和 AOP 是其两个关键特性,通过依赖注入和面向切面编程实现了高效的模块化和松耦合设计。Spring 容器管理着 Beans 的生命周期和配置,而核心模块为各种应用场景提供了丰富的功能支持。通过全面掌握这些核心概念,开发者可以更加高效地利用 Spring 框架开发企业级应用。
228 18
|
9月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
7月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
313 0
|
10月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
151 2
Spring高手之路25——深入解析事务管理的切面本质
|
10月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
332 8
|
10月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
848 2
|
10月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
231 2

推荐镜像

更多
  • DNS