SpringMVC 6+源码分析(四)DispatcherServlet实例化流程 3--(HandlerAdapter初始化)

一、概述

HandlerAdapter 是 Spring MVC 框架中的一个核心组件,它在 DispatcherServlet 和处理程序(handler)之间扮演适配器的角色。DispatcherServlet 接收到 HTTP 请求后,需要调用对应的 handler 来处理请求(如控制器方法),但不同 handler 的调用方式可能不同,例如:基于注解的控制器 或者 实现特定接口的控制器。HandlerAdapter 通过标准化接口屏蔽这些差异,确保 DispatcherServlet 能以统一方式调用任何 handler,从而提升框架的灵活性和扩展性。
框架默认的HandlerAdapter有四个,分别为:

  • RequestMappingHandlerAdapter:这是最常用的实现类,支持基于注解的控制器(如 @Controller 和@RequestMapping)。它通过反射调用注解方法,并处理参数绑定、返回值转换等。
  • SimpleControllerHandlerAdapter:支持实现 Controller 接口的handler。该接口要求handler 实现 ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) 方法。
  • HttpRequestHandlerAdapter:适配实现HttpRequestHandler 接口的 handler,常用于处理原始HTTP 请求(如资源处理)。
  • SimpleServletHandlerAdapter:支持 Servlet 类型的 handler,允许直接使用 ServletAPI处理请求。

二、初始化流程

系统在加载handlerAdapters 时,容器中是否已经存在对应的HandlerAdapter。如果不存在就加载默认的的四个HandlerAdapter。接下来 我们将以 RequestMappingHandlerAdapter为例,讲解整个初始化流程。

private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<>(matchingBeans.values());// We keep HandlerAdapters in sorted order.AnnotationAwareOrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.if (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet.properties");}}}

可以看到RequestMappingHandlerAdapter 继承了AbstractHandlerMethodAdapter 实现InitializingBean和BeanFactoryAware接口,所以对象被容器创建以后则将spring上下文设置到对应的实现方法中。
请添加图片描述

从源码中可以知道afterPropertiesSet() 第一个初始化的是ControllerAdvice(Controller 增强器),其主要作用是将扫描到的bean分类处理。

@Overridepublic void setBeanFactory(BeanFactory beanFactory) {if (beanFactory instanceof ConfigurableBeanFactory cbf) {this.beanFactory = cbf;}}@Overridepublic void afterPropertiesSet() {// Do this first, it may add ResponseBody advice beansinitControllerAdviceCache();initMessageConverters();if (this.argumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.initBinderArgumentResolvers == null) {List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);}if (this.returnValueHandlers == null) {List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);}}

先扫描过滤带有ControllerAdvice 注解的类,然后对对应的增强器进行分类并进行缓存。
如:参数增强器,数据绑定增强等。

private void initControllerAdviceCache() {if (getApplicationContext() == null) {return;}List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();for (ControllerAdviceBean adviceBean : adviceBeans) {Class<?> beanType = adviceBean.getBeanType();if (beanType == null) {throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);}Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);if (!attrMethods.isEmpty()) {this.modelAttributeAdviceCache.put(adviceBean, attrMethods);}Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);if (!binderMethods.isEmpty()) {this.initBinderAdviceCache.put(adviceBean, binderMethods);}if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {requestResponseBodyAdviceBeans.add(adviceBean);}}if (!requestResponseBodyAdviceBeans.isEmpty()) {this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);}if (logger.isDebugEnabled()) {int modelSize = this.modelAttributeAdviceCache.size();int binderSize = this.initBinderAdviceCache.size();int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {logger.debug("ControllerAdvice beans: none");}else {logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");}}}

接下来就是 初始化 消息转换器,它的左右就是将 http报文转化成json或者java对象。默认转化器有 ByteArrayHttpMessageConverter、StringHttpMessageConverter、AllEncompassingFormHttpMessageConverter。

	private void initMessageConverters() {if (!this.messageConverters.isEmpty()) {return;}this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(new StringHttpMessageConverter());this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());}

最后将初始化各类的Resolvers,有参数处理的Resolvers、数据绑定Resolvers,返回参数Resolvers。它们会根据不同的请求类型,数据类型,选择对应的处理器,对每个请求或者数据经行处理。这些Resolvers将对整个请求流程起到重要作用。

getDefaultArgumentResolvers()方法将加载默认的所有ArgumentResolvers。

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);// Annotation-based argument resolutionresolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ServletModelAttributeMethodProcessor(false));resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));resolvers.add(new RequestHeaderMapMethodArgumentResolver());resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new SessionAttributeMethodArgumentResolver());resolvers.add(new RequestAttributeMethodArgumentResolver());// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));resolvers.add(new RedirectAttributesMethodArgumentResolver());resolvers.add(new ModelMethodProcessor());resolvers.add(new MapMethodProcessor());resolvers.add(new ErrorsMethodArgumentResolver());resolvers.add(new SessionStatusMethodArgumentResolver());resolvers.add(new UriComponentsBuilderMethodArgumentResolver());if (KotlinDetector.isKotlinPresent()) {resolvers.add(new ContinuationHandlerMethodArgumentResolver());}// Custom argumentsif (getCustomArgumentResolvers() != null) {resolvers.addAll(getCustomArgumentResolvers());}// Catch-allresolvers.add(new PrincipalMethodArgumentResolver());resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));resolvers.add(new ServletModelAttributeMethodProcessor(true));return resolvers;}

getDefaultInitBinderArgumentResolvers()初始化默认参数数据绑定的 Resolver。

	private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(20);// Annotation-based argument resolutionresolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));resolvers.add(new RequestParamMapMethodArgumentResolver());resolvers.add(new PathVariableMethodArgumentResolver());resolvers.add(new PathVariableMapMethodArgumentResolver());resolvers.add(new MatrixVariableMethodArgumentResolver());resolvers.add(new MatrixVariableMapMethodArgumentResolver());resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));resolvers.add(new SessionAttributeMethodArgumentResolver());resolvers.add(new RequestAttributeMethodArgumentResolver());// Type-based argument resolutionresolvers.add(new ServletRequestMethodArgumentResolver());resolvers.add(new ServletResponseMethodArgumentResolver());// Custom argumentsif (getCustomArgumentResolvers() != null) {resolvers.addAll(getCustomArgumentResolvers());}// Catch-allresolvers.add(new PrincipalMethodArgumentResolver());resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));return resolvers;}

getDefaultReturnValueHandlers 方法初始化 返回值处理的Handler。

/*** Return the list of return value handlers to use including built-in and* custom handlers provided via {@link #setReturnValueHandlers}.*/private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(20);// Single-purpose return value typeshandlers.add(new ModelAndViewMethodReturnValueHandler());handlers.add(new ModelMethodProcessor());handlers.add(new ViewMethodReturnValueHandler());handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));handlers.add(new StreamingResponseBodyReturnValueHandler());handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));handlers.add(new HttpHeadersReturnValueHandler());handlers.add(new CallableMethodReturnValueHandler());handlers.add(new DeferredResultMethodReturnValueHandler());handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));// Annotation-based return value typeshandlers.add(new ServletModelAttributeMethodProcessor(false));handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));// Multi-purpose return value typeshandlers.add(new ViewNameMethodReturnValueHandler());handlers.add(new MapMethodProcessor());// Custom return value typesif (getCustomReturnValueHandlers() != null) {handlers.addAll(getCustomReturnValueHandlers());}// Catch-allif (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));}else {handlers.add(new ServletModelAttributeMethodProcessor(true));}return handlers;}

三、总结

到此整个初始化的大致流程已经就结束了,还有很多细节上的地方没有讲解到。后续在执行流程中,涉及到的在补充说明。在此过程中如存在纰漏或者错误,麻烦请支持,相互探讨相互学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91970.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91970.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【lucene】FastVectorHighlighter案例

下面给出一套可直接拷贝运行的 Lucene 8.5.0 FastVectorHighlighter 完整示例&#xff08;JDK 8&#xff09;&#xff0c;演示从建索引、查询到高亮的全过程。 > 关键点&#xff1a;字段必须 1. 存储原始内容&#xff08;setStored(true)&#xff09; 2. 开启 TermVecto…

C++返回值优化(RVO):高效返回对象的艺术

在C开发中&#xff0c;按值返回对象的场景十分常见&#xff08;如运算符重载、工厂函数等&#xff09;&#xff0c;但开发者常因担忧“构造/析构的性能开销”而陷入纠结&#xff1a;该不该返回对象&#xff1f;如何避免额外成本&#xff1f;本文将剖析痛点、拆解错误思路&#…

用 PyTorch 实现一个简单的神经网络:从数据到预测

PyTorch 是目前最流行的深度学习框架之一&#xff0c;以其灵活性和易用性受到开发者的喜爱。本文将带你从零开始&#xff0c;用 PyTorch 实现一个简单的神经网络&#xff0c;用于解决经典的 MNIST 手写数字分类问题。我们将涵盖数据准备、模型构建、训练和预测的完整流程&#…

四级页表通俗讲解与实践(以 64 位 ARM Cortex-A 为例)

&#x1f4d6; &#x1f3a5; B 站博文精讲视频&#xff1a;点击链接&#xff0c;配合视频深度学习 四级页表通俗讲解与实践&#xff08;以 64 位 ARM Cortex-A 为例&#xff09; 本文面向希望彻底理解现代 64 位架构下四级页表的开发者&#xff0c;结合 ARM Cortex-A 系列处理…

AI模型整合包上线!一键部署ComfyUI,2.19TB模型全解析

最近体验了AIStarter平台上线的AI模型整合包&#xff0c;包含2.19TB ComfyUI大模型&#xff0c;整合市面主流模型&#xff0c;一键部署ComfyUI&#xff0c;省去重复下载烦恼&#xff01;以下是使用心得和部署步骤&#xff0c;适合AI开发者参考。工具亮点这款AI模型整合包由熊哥…

灰色优选模型及算法MATLAB代码

电子装备试验方案优选是一个典型的多属性决策问题&#xff0c;通常涉及指标复杂、信息不完整、数据量少且存在不确定性的特点。灰色系统理论&#xff08;Grey System Theory&#xff09;特别擅长处理“小样本、贫信息”的不确定性问题&#xff0c;因此非常适合用于此类方案的优…

AI框架工具FastRTC快速上手6——视频流案例之物体检测(下)

一 前言 上一篇,我们实现了用YOLO对图片上的物体进行检测,并在图片上框出具体的对象并打出标签。但只是应用在单张图片,且还没用上FastRTC。 本篇,我们希望结合FastRTC的能力,实现基于YOLO的实时视频流的物体检测。 本篇文字将不会太多。学习完本篇,对比前面的文章,你…

PHP常见中高面试题汇总

一、 PHP部分 1、PHP如何实现静态化 PHP的静态化分为&#xff1a;纯静态和伪静态。其中纯静态又分为&#xff1a;局部纯静态和全部纯静态。 PHP伪静态&#xff1a;利用Apache mod_rewrite实现URL重写的方法&#xff1b; PHP纯静态&#xff0c;就是生成HTML文件的方式&#xff0…

基于Java AI(人工智能)生成末日题材的实践

Java AI 生成《全球末日》文章的实例 使用Java结合AI技术生成《全球末日》题材的文章可以通过多种方式实现,包括调用预训练模型、使用自然语言处理库或结合生成式AI框架。以下是30个实例的生成方法和示例代码片段。 调用预训练模型(如GPT-3或GPT-4) 使用OpenAI API生成末日…

针对软件定义车载网络的动态服务导向机制

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

Pytorch实现婴儿哭声检测和识别

Pytorch实现婴儿哭声检测和识别 目录 Pytorch实现婴儿哭声检测识别 1. 项目说明 2. 数据说明 &#xff08;1&#xff09;婴儿哭声语音数据集 &#xff08;2&#xff09;自定义数据集 3. 模型训练 &#xff08;1&#xff09;项目安装 &#xff08;2&#xff09;准备Tra…

海信IP810N/海信IP811N_海思MV320-安卓9.0主板-TTL烧录包-可救砖

海信IP810N&#xff0f;海信IP811N_海思MV320处理器-安卓9主板-TTL烧录包-可救砖准备工作&#xff1a;TTL线自备跑码工具【putty跑码中文版】路径&#xff1a;【工具大全】-【putty跑码中文版】测试跑码以后将跑码窗口关闭&#xff1b;然后到下方下载烧录工具并大致看下教程烧录…

Go 中的 interface{} 与 Java 中的 Object:相似之处与本质差异

在软件系统开发中&#xff0c;“通用类型”的处理是各语言设计中不可忽视的一部分。Java 使用 Object&#xff0c;Go 使用 interface{}&#xff0c;它们都可以容纳任意类型的值&#xff0c;是实现动态行为或通用容器的基础类型。然而&#xff0c;虽然两者在使用层面看似相似&am…

Docker-07.Docker基础-数据卷挂载

一.案例首先我们通过一则案例来引出问题。我们要修改nginx容器内的html目录下的index.html文件&#xff0c;并且要将静态资源部署到nginx的html目录&#xff0c;就要首先知道该html目录的所在位置。我们首先查看nginx镜像的帮助文档&#xff0c;这里就是将有关静态资源目录的&a…

数据结构(三)双向链表

一、什么是 make 工具&#xff1f;make 是一个自动化构建工具&#xff0c;主要用于管理 C/C 项目的编译和链接过程。它通过读取 Makefile 文件中定义的规则&#xff0c;自动判断哪些文件被修改&#xff0c;并仅重新编译这些部分&#xff0c;从而大幅提高构建效率。二、什么是 M…

如何在没有iCloud的情况下将联系人转移到新iPhone?

升级到新 iPhone 后&#xff0c;设置已完成&#xff0c;想在不使用 iCloud 的情况下将联系人从 iPhone 转移到 iPhone 吗&#xff1f;别担心。还有其他 5 种方法可以帮助您轻松地将联系人转移到新 iPhone。这样&#xff0c;您就无需再次重置新设备了。第 1 部分&#xff1a;如何…

SpringBoot3.x入门到精通系列:4.2 整合 Kafka 详解

SpringBoot 3.x 整合 Kafka 详解 &#x1f3af; Kafka简介 Apache Kafka是一个分布式流处理平台&#xff0c;主要用于构建实时数据管道和流应用程序。它具有高吞吐量、低延迟、可扩展性和容错性等特点。 核心概念 Producer: 生产者&#xff0c;发送消息到Kafka集群Consumer: 消…

Android audio之 AudioDeviceInventory

1. 类介绍 AudioDeviceInventory 是 Android 音频系统中的一个核心类,位于 frameworks/base/services/core/java/com/android/server/audio/ 路径下。它负责 管理所有音频设备的连接状态,包括设备的添加、移除、状态更新以及策略应用。 设备连接状态管理:记录所有已连接的音…

系统设计入门:成为更优秀的工程师

系统设计入门指南 动机 现在你可以学习如何设计大规模系统&#xff0c;为系统设计面试做准备。本指南包含的是一个有组织的资源集合&#xff0c;旨在帮助你了解如何构建可扩展的系统。 学习设计大规模系统 学习如何设计可扩展系统将帮助你成为更优秀的工程师。系统设计是一个…

Pandas数据分析工具基础

文章目录 0. 学习目标 1. Pandas的数据结构分析 1.1 Series - 序列 1.1.1 Series概念 1.1.2 Series类的构造方法 1.1.3 创建Series对象 1.1.3.1 基于列表创建Series对象 1.1.3.2 基于字典创建Series对象 1.1.4 获取Series对象的数据 1.1.5 Series对象的运算 1.1.6 增删Series对…