首页 > 其他分享 >SpringMVC执行流程

SpringMVC执行流程

时间:2024-10-19 11:17:17浏览次数:8  
标签:执行 请求 SpringMVC 流程 视图 拦截器 处理器 DispatcherServlet response

SpringMVC执行流程

文章目录

1. Spring常用组件


1.1 DispatcherServlet:前端控制器

DispatcherServlet是Spring MVC框架的核心,相当于整个框架的门面。它负责接收用户的请求,并根据请求类型、URL等信息调用相应的处理器,最后将处理结果返回给用户。

  • 统一处理请求和响应,实现请求的统一入口和出口。
  • 控制整个请求处理流程,协调各个组件协同工作。
  • 提供强大的配置机制,通过配置文件或注解的方式定义请求映射和处理器。
  • 支持多种请求处理方式,如Servlet、Servlet3.0异步、WebFlux等。

1.2 HandlerMapping:处理器映射器

HandlerMapping负责根据请求信息(URL、HTTP方法等)找到对应的处理器。

  • RequestMappingHandlerMapping:根据Controller类或方法上的@RequestMapping注解进行映射。
  • SimpleUrlHandlerMapping:根据URL进行映射。

HandlerMapping的作用

  • 根据请求信息快速定位处理器,提高请求处理效率。
  • 支持多种映射方式,满足不同的业务需求。
  • 提供灵活的映射规则,如后缀映射、路径匹配等。

1.3 Handler:处理器

Handler是开发者编写的控制器,负责接收请求并处理业务逻辑。在Spring MVC中,处理器通常以Controller、Service、DAO的形式存在。

  • 处理业务逻辑,返回处理结果。
  • 支持多种请求处理方式,如直接返回数据、跳转页面、重定向等。
  • 可以方便地与Spring框架的其他组件(如Service、DAO)集成。

1.4 HandlerAdapter:处理器适配器

HandlerAdapter负责调用处理器的方法,并将处理结果返回给DispatcherServlet。

  • DispatcherServletHandlerAdapter:适配Controller接口。
  • SimpleControllerHandlerAdapter:适配Servlet。

HandlerAdapter的作用

  • 提供统一的调用接口,方便开发者编写处理器。
  • 支持多种处理器类型,如Controller、Servlet等。
  • 提高代码复用性,降低开发难度。

1.5 ViewResolver:视图解析器

ViewResolver负责将处理结果转换为视图,并将视图渲染给用户。

  • InternalResourceViewResolver:解析JSP视图。
  • ThymeleafViewResolver:解析Thymeleaf视图。

ViewResolver的作用

  • 将处理结果转换为视图,提供丰富的视图支持。
  • 支持多种视图类型,如JSP、Thymeleaf、Freemarker等。
  • 提高代码复用性,降低开发难度。

1.6 View:视图

View负责将处理结果展示给用户。

  • JspView:展示JSP视图。
  • ThymeleafView:展示Thymeleaf视图。
  • RedirectView:重定向到其他URL。

View的作用

  • 将处理结果展示给用户,提供丰富的视图支持。
  • 支持多种视图类型,如JSP、Thymeleaf、Freemarker等。
  • 提高代码复用性,降低开发难度。

2. DispatcherServlet的初始化与生命周期


DispatcherServlet作为Spring MVC框架的核心,其本质是一个Servlet,因此它遵循Servlet的生命周期。在宏观层面上,其调度过程是依托于Servlet的生命周期来进行的。

在这里插入图片描述

2.1 初始化WebApplicationContext

DispatcherServlet的初始化过程首先涉及到WebApplicationContext的创建。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    // ...(省略部分代码)

    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        wac = createWebApplicationContext(rootContext);
    }

    // ...(省略部分代码)

    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            // 刷新WebApplicationContext
            onRefresh(wac);
        }
    }

    // ...(省略部分代码)

    return wac;
}

在上述代码中,首先尝试获取已经存在的WebApplicationContext实例。如果不存在,则创建一个新的WebApplicationContext实例,并通过createWebApplicationContext方法进行初始化。

2.2 创建WebApplicationContext

创建WebApplicationContext的过程涉及到反射和配置设置。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException(
            "Fatal initialization error in servlet with name '" + getServletName() +
            "': custom WebApplicationContext class [" + contextClass.getName() +
            "] is not of type ConfigurableWebApplicationContext");
    }
    // 通过反射创建 IOC 容器对象
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    // 设置环境、父容器、配置位置等
    wac.setEnvironment(getEnvironment());
    wac.setParent(parent);
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
        wac.setConfigLocation(configLocation);
    }
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}

在此步骤中,通过反射创建一个ConfigurableWebApplicationContext实例,并设置其环境、父容器和配置位置等信息。

2.3 DispatcherServlet初始化策略

在创建并初始化WebApplicationContext之后,DispatcherServlet会调用initStrategies方法来初始化其各个组件。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   initHandlerMappings(context);
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}

在这段代码中,DispatcherServlet会依次初始化以下策略:

  • 文件上传解析器(MultipartResolver)
  • 区域设置解析器(LocaleResolver)
  • 主题解析器(ThemeResolver)
  • 处理器映射器(HandlerMappings)
  • 处理器适配器(HandlerAdapters)
  • 异常处理器(HandlerExceptionResolvers)
  • 请求到视图名转换器(RequestToViewNameTranslator)
  • 视图解析器(ViewResolvers)
  • FlashMap管理器(FlashMapManager)

3. DispatcherServlet请求处理流程详解


3.1 processRequest()

FrameworkServlet 类继承自 HttpServlet,并重写了 service()doXxx() 方法。这些方法最终会调用 processRequest(request, response) 来处理请求。

  • 所在类:org.springframework.web.servlet.FrameworkServlet
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // ...(省略初始化和上下文设置代码)

    try {
        // 执行服务,doService()是一个抽象方法,在DispatcherServlet中进行了重写
        doService(request, response);
    }
    finally {
        // ...(省略清理和日志记录代码)
    }
}

在这个方法中,DispatcherServlet会初始化一些必要的上下文,如Locale、RequestAttributes等,并最终调用 doService() 方法来处理实际的请求。

3.2 doService()

doService() 方法是DispatcherServlet处理请求的核心方法,它负责将请求映射到合适的处理器(Handler),并执行处理器逻辑。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // ...(省略请求日志和属性设置代码)

    try {
        // 处理请求和响应
        doDispatch(request, response);
    }
    finally {
        // ...(省略清理代码)
    }
}

doService() 方法中,首先会设置一些框架对象,如WebApplicationContext、LocaleResolver、ThemeResolver等,然后调用 doDispatch() 方法来执行实际的请求处理。

3.3 doDispatch()

doDispatch() 方法负责将请求分发给相应的处理器,并处理返回的 ModelAndView 对象。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // ...(省略检查文件上传和解析请求路径代码)

    try {
        // Determine handler for the current request.
        HandlerExecutionChain mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
        }

        // Determine handler adapter for the current request.
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

        // 调用拦截器的preHandle()
        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
        }

        // Actually invoke the handler.
        ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        // 调用拦截器的postHandle()
        mappedHandler.applyPostHandle(processedRequest, response, mv);

        // 后续处理:处理模型数据和渲染视图
        processDispatchResult(processedRequest, response, mappedHandler, mv, null);
    }
    catch (Exception ex) {
        processDispatchResult(processedRequest, response, null, null, ex);
    }
    catch (Throwable err) {
        processDispatchResult(processedRequest, response, null, null, new NestedServletException("Handler processing failed", err));
    }
}

doDispatch() 方法中,首先通过 getHandler() 方法找到对应的处理器,然后通过 getHandlerAdapter() 方法获取处理器适配器。接着,调用拦截器的 preHandle() 方法,执行处理器方法,并获取 ModelAndView 对象。之后,调用拦截器的 postHandle() 方法,最后通过 processDispatchResult() 方法处理模型数据和渲染视图。

3.4 processDispatchResult()

processDispatchResult() 方法负责处理 ModelAndView 对象,包括渲染视图和处理异常。

  • 所在类:org.springframework.web.servlet.DispatcherServlet
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {
    // ...(省略异常处理代码)

    if (mv != null && !mv.wasCleared()) {
        // 处理模型数据和渲染视图
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    }
    else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    // 调用拦截器的afterCompletion()
    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

processDispatchResult() 方法中,如果 ModelAndView 对象不为空且未被清除,则会处理模型数据和渲染视图。如果发生异常,则会进行处理,并清理错误请求属性。最后,调用拦截器的 afterCompletion() 方法。

4. SpringMVC执行流程解析


Spring MVC框架的执行流程是自动化且高度可配置的

  1. 请求捕获与解析
    用户向服务器发送请求,该请求首先被Spring MVC的前端控制器 DispatcherServlet 捕获。

  2. URL映射解析
    DispatcherServlet解析请求的URL,获取请求资源标识符(URI)。然后,系统判断该URI是否已经配置了映射关系:

    a. 映射不存在

    • 如果没有配置映射,系统会检查是否启用了 mvn:default-servlet-handler
    • 如果没有配置 default-servlet-handler,则控制台会显示映射找不到的错误,客户端会收到404错误。
    • 如果启用了 default-servlet-handler,DispatcherServlet会将请求转发到默认的Servlet处理静态资源(如JS、CSS、HTML文件),如果资源不存在,客户端同样会收到404错误。
  3. HandlerMapping查找
    如果存在映射,DispatcherServlet会调用 HandlerMapping 获取与请求URI对应的处理器(Handler)配置信息,包括处理器对象及其关联的拦截器。这些信息被封装成 HandlerExecutionChain 对象返回。

  4. HandlerAdapter选择
    根据获取到的处理器,DispatcherServlet会选择一个合适的 HandlerAdapter。HandlerAdapter负责调用处理器的方法,并处理返回的结果。

  5. 拦截器预处理
    如果配置了拦截器,DispatcherServlet会先执行拦截器的 preHandle() 方法。

  6. 处理器方法调用
    DispatcherServlet提取请求中的模型数据,填充处理器(Controller)的入参。在这个过程中,Spring MVC会自动处理以下任务:

    • 消息转换:将请求消息(如JSON、XML等)转换为Java对象。
    • 数据转换:对请求消息进行数据转换,如将字符串转换为整数或双精度浮点数。
    • 数据格式化:对请求消息进行格式化处理,如将字符串转换为格式化的数字或日期。
    • 数据验证:验证数据的有效性,如长度、格式等,并将验证结果存储到 BindingResultError 对象中。
  7. ModelAndView生成
    处理器(Controller)方法执行完成后,向DispatcherServlet返回一个 ModelAndView 对象。该对象包含视图名称和模型数据。

  8. 拦截器后处理
    此时,系统会执行拦截器的 postHandle() 方法。

  9. 视图解析与渲染
    根据返回的 ModelAndView,系统选择一个合适的 ViewResolver 进行视图解析。ViewResolver负责将视图名称解析为具体的视图对象,并根据模型数据渲染视图。

  10. 拦截器完成处理
    渲染视图完成后,执行拦截器的 afterCompletion() 方法。

  11. 响应客户端
    最后,将渲染结果返回给客户端。

标签:执行,请求,SpringMVC,流程,视图,拦截器,处理器,DispatcherServlet,response
From: https://blog.csdn.net/2301_77207909/article/details/143038207

相关文章

  • Kubernetes部署Prometheus并实现自定义指标HPA(安装、配置、实现全流程)
    1.安装kube-prometheusKube-Prometheus是一个开箱即用的监控解决方案,用于监控Kubernetes集群。它集成了Prometheus、Prometheus-Adapter、Alertmanager和一系列的导出器(exporters),使你能够轻松地收集和可视化集群中各种资源的监控数据。1.1克隆kube-prometheus仓库gitclon......
  • hive执行SQL提示:Error while processing statement:FAILED:Execution Error, return c
    遇到Hive执行SQL时提示Errorwhileprocessingstatement:FAILED:ExecutionError,returncode1fromorg.apache.hadoop.hive.ql.exec.tez.TezTask的错误,通常意味着在执行Tez任务时出现了问题。这个错误可能由多种原因引起,包括但不限于配置问题、资源限制、数据问......
  • 【GESP】C++一级练习BCQM3048,顺序执行、逆推运算
    一道根据结果,一步一步逆推之前结果的题,完全顺序语句执行题目题解详见:https://www.coderli.com/gesp-1-bcqm3048/【GESP】C++一级练习BCQM3048,顺序执行、逆推运算|OneCoder一道根据结果,一步一步逆推之前结果的题,完全顺序语句执行。https://www.coderli.com/gesp-1-bcqm3048/......
  • 【高级SQL 十条调优技巧含实例可执行命令】
    高级SQL技巧是在SQL查询和操作方面进行更高级的优化和功能实现的技巧。以下是一些常见的高级SQL技巧:使用窗口函数:窗口函数是一种强大的SQL功能,它允许在查询结果上执行聚合函数,同时保留原始数据行。使用窗口函数可以实现排序、分组和计算行号等功能。窗口函数:SELE......
  • 全面解读大模型备案流程及重点、难点【+附件材料】
    本文详解大模型备案流程,旨在指引企业和开发者顺利完成备案,确保企业成功拿到大模型备案号。一、政策要求做大模型备案大模型备案是中国国家互联网信息办公室为加强生成式人工智能服务的管理,确保用户权益得到充分保护,以及保障国家安全和社会秩序稳定而实施的一项关键性政策。......
  • Vue3 - 详细实现移动端H5网页调用摄像头拍照功能,微信公众号网页h5页面打开本地摄像头
    前言PC网站端,请访问这篇文章。在vue3手机移动端开发中,详解H5页面/微信公众号网页调用浏览器摄像头并拍照完整示例,在手机浏览器上开启摄像头并拍照上传服务器或保存到本地功能(实时预览使用图片临时路径或base64数据),切换转换前置摄像头与后置摄像头,vue3手机H5打开摄像......
  • 第36篇 linux服务器上启动framework应用程序流程
    framework开发的应用程序,一般是不会在linux服务器上运行的,但是我们可以通过mono进行应用部署1.查看linux服务上是否已经安装mono-core方式1:rpm命令查看rpm-qa|grepmono-core有结果返回,说明已经安装方式2:使用yumlistinstalledyumlistinstalled|grepmono-core......
  • Android Framework AMS(08)service组件分析-2(startService和StopService关键流程分析)
    该系列文章总纲链接:专题总纲目录AndroidFramework总纲本章关键点总结&说明:说明:上一章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。本章节主要关注service组件启动方式的一种:startService启动方式,分析关键API......
  • Android Framework AMS(09)service组件分析-3(bindService和unbindService关键流程分析)
    该系列文章总纲链接:专题总纲目录AndroidFramework总纲本章关键点总结&说明:说明:上上一章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。上一章节我们关注了service组件启动方式的一种:startService启动方式。本章......
  • 计算机网络基础(2)---网络传输基本流程与Socket编程预备
    个人主页:C++忠实粉丝欢迎点赞......