当前位置: 首页 > article >正文

Spring Mvc 基础源码分析

一、onRefresh 初始化

在 Spring MVC 中,onRefreshFrameworkServlet 类中的一个关键方法,负责在 Spring Web 应用的容器刷新时,初始化与 Web 相关的组件,包括加载和配置 DispatcherServlet。这一过程是 Spring MVC 启动和运行的核心部分,涉及到多个重要步骤和组件的初始化。

onRefresh 方法主要负责初始化 Spring MVC 框架中与 HTTP 请求处理相关的各种对象,如处理器映射(Handler Mapping)、视图解析器(View Resolver)等。这个方法在 Spring 的容器(例如 ApplicationContext)刷新之后自动被调用,确保所有的 Web 组件都已经准备就绪,可以处理进来的请求。

初始化过程概览
  1. Spring 容器的启动

    • 在 Web 应用程序中,当 WebApplicationContext 被初始化时,它首先加载 Spring 配置文件或配置类,注册 Bean 定义,然后刷新容器。
  2. 调用 onRefresh

    • FrameworkServletonRefresh 方法在 WebApplicationContext 刷新后被调用。
    • 这个方法是由 initWebApplicationContext() 触发的,该方法检查 Servlet 的初始化参数,配置 ApplicationContext。
  3. 初始化 Web 特有的组件

    • onRefresh 的实现中,DispatcherServlet 通过重写这个方法来初始化 Web 上下文的特定基础设施,如:
      • HandlerMapping:用于确定哪个控制器应该处理哪个请求。
      • HandlerAdapter:用于执行处理器方法。
      • ViewResolver:用于解析视图名称到具体的视图实现。
      • MessageConverter:用于请求和响应的数据绑定。
      • LocaleResolverThemeResolver 等:处理本地化和主题相关的配置。
  4. 注册 Web 相关组件

    • DispatcherServlet 会查找定义在 WebApplicationContext 中的所有组件,并将它们注册为局部的 Web MVC 配置,例如多个 HandlerMappingViewResolver
  5. 设置必要的属性

    • DispatcherServlet 还会设置一些必要的属性和配置,如默认语言解析器、文件上传处理等。
代码示例

下面是 DispatcherServletonRefresh 方法的一个简化的示例,展示了如何初始化一些核心的 Web MVC 组件:

@Override
protected void onRefresh(ApplicationContext context) {
    // 初始化 DispatcherServlet 特有的基础设施
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initViewResolvers(context);
    initMessageConverters(context);
    // 其他必要的初始化代码...
}

这个方法和其他的 init* 方法一起构成了 Spring MVC 的 Web 层的核心功能,确保所有必要的组件都已经就绪,可以对 HTTP 请求做出响应。

二、initStrategies()中进⾏9⼤组件的初始化

在 Spring MVC 的 DispatcherServlet 中,initStrategies 方法负责初始化 Web 应用程序的九大核心组件。这些组件是 Spring MVC 框架处理请求的基础,各自承担着特定的职责。下面是这九大组件的详细介绍及其在 DispatcherServlet 中的初始化过程。

1. HandlerMapping

负责将请求映射到处理器(Controllers)。这个组件决定了哪个 Controller 应该处理传入的请求

protected void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        // 从 ApplicationContext 中获取所有 HandlerMapping Beans
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // 根据优先级排序
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    // 如果没有定义,则使用默认配置
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        log.info("No HandlerMappings found in servlet '" + getServletName() + "': using default");
    }
}
2. HandlerAdapter

允许 DispatcherServlet 使用任何类型的处理器。主要职责是调用 Controller 的方法来处理请求。

protected void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;

    if (this.detectAllHandlerAdapters) {
        Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
                context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        log.info("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
    }
}
3. HandlerExceptionResolver

用于解析在请求处理过程中抛出的异常。

protected void initHandlerExceptionResolvers(ApplicationContext context) {
    this.handlerExceptionResolvers = null;

    if (this.detectAllHandlerExceptionResolvers) {
        Map<String, HandlerExceptionResolver> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
        }
    }
    if (this.handlerExceptionResolvers == null) {
        this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
        log.info("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
    }
}
4. ViewResolver

解析视图名到实际视图的转换,用于渲染模型数据。

5. RequestToViewNameTranslator

根据请求来决定视图的名称,通常用于处理方法不直接返回视图名时。

6. LocaleResolver

处理国际化,决定当前请求使用的区域设置。

7. ThemeResolver

处理主题解析,如决定渲染哪个主题的视图。

8. MultipartResolver

如果请求类型是 multipart/form-data,则处理文件上传请求。

9. FlashMapManager

管理 Flash 属性,通常用于重定向之间传递参数。

三、DispatcherServlet

DispatcherServlet 是 Spring MVC 的核心组件,负责处理所有 HTTP 请求。它是一个前端控制器(Front Controller),意味着它提供了一个集中的请求处理机制,使所有的请求都通过它进行处理。这样可以统一请求处理行为,便于管理和配置。

DispatcherServlet 工作流程概览
  1. 请求接收DispatcherServlet 接收到 HTTP 请求。
  2. 请求解析:解析请求,如提取 URL 路径、解析查询参数、处理表单数据等。
  3. 处理器映射(Handler Mapping):根据请求找到对应的处理器(Controller)。
  4. 处理器适配(Handler Adapter):用于调用处理器的适配器,使不同的处理器可以按统一方式调用。
  5. 处理器执行:执行找到的处理器(Controller),处理业务逻辑。
  6. 视图解析(View Resolver):处理器处理完后,根据其返回值确定下一步处理,通常是解析处理结果并选择一个视图进行渲染。
  7. 视图渲染:渲染视图,将模型数据展示在视图页面上。
  8. 返回响应:将生成的页面或其他类型的响应返回给客户端。
DispatcherServlet 的主要方法

DispatcherServlet 继承自 HttpServlet,其核心方法是 doDispatch(HttpServletRequest request, HttpServletResponse response),这个方法包括了上述的大部分流程。下面是该方法的简化逻辑:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    ModelAndView mv = null;

    try {
        // 检查是否是文件上传请求(Multipart)
        processedRequest = checkMultipart(request);
        
        // 确定此请求的处理器。
        mappedHandler = getHandler(processedRequest);
        if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
        }

        // 获取处理器适配器
        HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

        // 实际的处理器执行
        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

        // 视图渲染
        processDispatchResult(processedRequest, response, mappedHandler, mv, null);
    } catch (Exception ex) {
        dispatchException(processedRequest, response, mappedHandler, ex);
    } finally {
        // 清理任何资源
        cleanup(processedRequest, response, mappedHandler);
    }
}
  • HandlerMapping:决定由哪个处理器(Controller)处理请求。
  • HandlerAdapter:提供了一个适配器,用以调用 Spring MVC 中的处理器。这使得 DispatcherServlet 能够调用任何类型的处理器。
  • ViewResolver:解析字符串形式的视图名到具体的 View 实现。
  • MultipartResolver:解析多部分请求(主要用于文件上传)。
扩展点
  • Interceptor(拦截器):在请求被处理器处理前后进行额外的操作,如身份验证、日志记录等。
  • LocaleResolverThemeResolver:处理国际化和主题解析。

DispatcherServlet 的设计高度集成且模块化,提供了许多扩展接口,使得开发者可以轻松地添加或修改功能。它通过委派模型与各种策略接口实现了强大的灵活性和扩展性,是 Spring MVC 框架的关键部分。

四、HandlerAdapter 中的适配器模式

在 Spring MVC 中,HandlerAdapter 的使用是一个典型的适配器模式应用。适配器模式主要用于使原本由于接口不兼容而不能一起工作的类可以协同工作。在 Spring MVC 的上下文中,这种模式允许 DispatcherServlet 调用任何类型的处理器(Controller),即使这些处理器可能具有不同的方法签名和处理逻辑。

HandlerAdapter 的角色和功能

HandlerAdapter 的主要功能是桥接 DispatcherServlet 和多种不同的处理器(Controllers)。由于 Spring 允许使用多种类型的处理器,例如 @Controller 注解的类、HTTP 请求处理方法、Controller 接口的实现等,这些处理器类型在如何接收请求和返回响应方面可能会有所不同。HandlerAdapter 负责将 DispatcherServlet 的调用转换为特定类型处理器可以接受的形式。

使用适配器模式的优势
  1. 灵活性:通过 HandlerAdapter,Spring MVC 能够支持多种类型的处理器,开发者可以根据需要选择最适合项目的控制器类型。例如,可以轻松切换或混用基于注解的控制器和实现 Controller 接口的传统控制器。

  2. 可扩展性:开发者可以定义自己的 HandlerAdapter 来支持自定义的处理器类型。这增加了框架的扩展性,使得可以在不修改框架核心代码的情况下增加新的功能。

  3. 解耦DispatcherServlet 不需要知道处理器的具体实现细节,只需要通过 HandlerAdapter 与之交互。这降低了组件间的耦合度,使得系统更加模块化。

Spring MVC 中 HandlerAdapter 的实现

Spring 提供了几种内置的 HandlerAdapter 实现:

  • RequestMappingHandlerAdapter:用于处理使用 @RequestMapping 注解的方法。
  • HttpRequestHandlerAdapter:用于处理实现了 HttpRequestHandler 接口的处理器。
  • SimpleControllerHandlerAdapter:用于处理实现了 Controller 接口的传统控制器。

每种 HandlerAdapter 实现都有自己的处理逻辑,但它们都遵循相同的基本模式:接收 DispatcherServlet 的调用请求,将其适配为特定处理器可以理解的形式,然后调用处理器的方法,并将结果返回给 DispatcherServlet


http://www.kler.cn/a/325949.html

相关文章:

  • 分布式cap理论学习
  • MATLAB向量元素的引用
  • 了解什么是Python(简介)
  • DB Type
  • gitlab和jenkins连接
  • torchvision库在进行图片转换操作中报antialias参数没有显式设置会导致不同图片后端中的值不统一的警告信息
  • OceanBase 关于一号表笔记与ERROR 1060(42S21)问题
  • 表驱法优化代码
  • 入职2年的程序员,被劝退了!年纪大了,感觉好绝望!
  • Studying-图论包含的算法总结
  • [Python学习日记-31] Python 中的函数
  • Java开发:文件上传和下载
  • PCL 移动立方体重建(HOPPE)
  • STM32引脚PB3、PB4、PA15作为输入输出的特殊配置
  • mysql代理服务器
  • 自然语言处理实战项目
  • MinIO使用客户端进行桶和对象的管理
  • OpenCV视频I/O(1)视频采集类VideoCapture介绍
  • Mybatis-Mapper接口方式
  • SpringBoot依赖之Microsoft SQL Server Driver
  • 谈谈Redisson分布式锁的底层实现原理
  • 怎么提取视频里的音频?非常简单的提取音频方法
  • 上下位关系自动检测方法(论文复现)
  • Stargazers Ghost Network在GitHub平台上的隐性威胁
  • 大数据复习知识点4
  • 深度估计任务中的有监督和无监督训练