Spring Mvc 基础源码分析

news/2024/12/21 22:10:04/

一、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 组件:

java">@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 应该处理传入的请求

java">protected void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;if (this.detectAllHandlerMappings) {// 从 ApplicationContext 中获取所有 HandlerMapping BeansMap<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 的方法来处理请求。

java">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

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

java">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),这个方法包括了上述的大部分流程。下面是该方法的简化逻辑:

java">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.ppmy.cn/news/1533895.html

相关文章

【已解决】【Hadoop】找到java环境路径

在 Hadoop 环境中&#xff0c;Java 环境路径通常指的是 Java 的安装目录&#xff0c;因为 Hadoop 是用 Java 编写的&#xff0c;并且需要 Java 运行时环境&#xff08;JRE&#xff09;或 Java 开发工具&#xff08;JDK&#xff09;来运行。以下是几种方法来找到 Java 环境路径&…

go channel的使用

channel是goroutine之间通信的管道&#xff0c;可以将值从一个goroutine发送到channel&#xff0c;另一个goroutine从channel接收到这些值。 Do not communicate by sharing memory; instead, share memory by communicating. 创建channel //无缓存channel ch : make(chan int…

通信工程学习:什么是NFS网络文件系统

NFS&#xff1a;网络文件系统 NFS&#xff08;Network File System&#xff09;&#xff0c;即网络文件系统&#xff0c;是一种用于在计算机网络上共享文件的协议。它允许一个计算机系统通过网络将其文件和存储设备共享给其他计算机系统&#xff0c;使得这些系统可以像访问本地…

C++随心记

C随心记 C中的 CONST C中的const是表示不可修改 int main() {/* 对于变量而言 */// 不可修改的常量const int A 10;// 不可修改的指针指向const int* pointer_0 nullptr;int const* poniter_1 nullptr;// 不可修改指针指向的内容int* const poniter_2 nullptr; }const也…

中九无科研无竞赛保研经验帖——上交软院、中科大计算机、复旦工程硕、南大工程硕、浙大软件

本人bg: 学校&#xff1a;中九软件工程rk&#xff1a;夏令营5%&#xff0c;预推免3%&#xff08;都是写的预估排名&#xff09;六级&#xff1a;480&#xff0c; 四级&#xff1a;540科研&#xff1a;无竞赛&#xff1a;美赛M&#xff0c;以及水赛国三、省二若干 保研前期没有…

LeetCode题练习与总结:丑数--263

一、题目描述 丑数 就是只包含质因数 2、3 和 5 的正整数。 给你一个整数 n &#xff0c;请你判断 n 是否为 丑数 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;n 6 输出&#xff1a;true 解释&#xff1…

航顺芯片HK32MCU受邀出席汽车芯片国产化与技术创新闭门研讨会

[中国&#xff0c;北京&#xff0c;2024年9月21日]近日&#xff0c;深圳市航顺芯片技术研发有限公司&#xff08;以下简称“航顺芯片”&#xff09;产品总监郑增忠受邀出席由中国设备管理协会新能源汽车产业发展促进中心主办的“汽车芯片国产化与技术创新闭门研讨会”。 会上航…

VisionTS:基于时间序列的图形构建高性能时间序列预测模型,利用图像信息进行时间序列预测

构建预训练时间序列模型时面临的主要挑战是什么&#xff1f;获取高质量、多样化的时间序列数据。目前构建基础预测模型主要有两种方法&#xff1a; 迁移学习LLM&#xff1a;通过针对时间序列任务定制的微调或分词策略&#xff0c;重新利用预训练的大型语言模型&#xff08;LLM…