SpringMVC系列七:RequestMappingHandlerAdapter的初始化

Spring-MVC配置项目框架、注释@Repository/@Service/@Controller/@RequestMapping入门讲解 主要讲解Mvc项目框架配置,以及部分后端基本运用的注解 阅读详情

RequestMappingHandlerAdapter的初始化

RequestMappingHandlerAdapter的类图

在这里插入图片描述

注入RequestMappingHandlerAdapter并实例化

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
   RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
   adapter.setContentNegotiationManager(mvcContentNegotiationManager());
   // 设置 HttpMessageConverter
   adapter.setMessageConverters(getMessageConverters());
   // 设置 ConversionService 以及 Validator
   adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
   adapter.setCustomArgumentResolvers(getArgumentResolvers());
   adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

   if (jackson2Present) {
      adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
      adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
   }

   AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
   configureAsyncSupport(configurer);
   if (configurer.getTaskExecutor() != null) {
      adapter.setTaskExecutor(configurer.getTaskExecutor());
   }
   if (configurer.getTimeout() != null) {
      adapter.setAsyncRequestTimeout(configurer.getTimeout());
   }
   adapter.setCallableInterceptors(configurer.getCallableInterceptors());
   adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

   return adapter;
}

添加 HttpMessageConverter

protected final List<HttpMessageConverter<?>> getMessageConverters() {
   if (this.messageConverters == null) {
      this.messageConverters = new ArrayList<>();
      configureMessageConverters(this.messageConverters);
      if (this.messageConverters.isEmpty()) {
         // 加入 defaultHttpMessageConverter,通常直接删除
         addDefaultHttpMessageConverters(this.messageConverters);
      }
      // 重写该方法
      extendMessageConverters(this.messageConverters);
   }
   return this.messageConverters;
}

加入 stringHttpMessageConverter 和 fastJsonHttpMessageConverter

protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
   converters.clear();
   converters.add(stringHttpMessageConverter());
   converters.add(fastJsonHttpMessageConverter());
}

添加 ConversionService

protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
   ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
   // 设置 ConversionService
   initializer.setConversionService(mvcConversionService());
   // 设置 Validator
   initializer.setValidator(mvcValidator());
   MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
   if (messageCodesResolver != null) {
      initializer.setMessageCodesResolver(messageCodesResolver);
   }
   return initializer;
}
@Bean
public FormattingConversionService mvcConversionService() {
   FormattingConversionService conversionService = new DefaultFormattingConversionService();
   // 添加自定义的 Converter
   addFormatters(conversionService);
   return conversionService;
}

其中 DefaultFormattingConversionService 含有大量的 Converter 用来参数转换

调用 afterPropertiesSet 进行初始化

因为RequestMappingHandlerAdapter实现InitializingBean接口所以在spring初始化的时候调用在RequestMappingHandlerAdapter的afterPropertiesSet方法

@Override
public void afterPropertiesSet() {
   // Do this first, it may add ResponseBody advice beans
   // 解析标注了 @ControllerAdvice 的类中的 @InitBinder @ModelAttribute 方法
   initControllerAdviceCache();

   // 设置 argumentResolvers
   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);
   }
   // 设置 returnValueHandlers
   if (this.returnValueHandlers == null) {
      List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
   }
}

解析标注了 @ControllerAdvice 的类中的 @InitBinder @ModelAttribute 方法

private void initControllerAdviceCache() {
   if (getApplicationContext() == null) {
      return;
   }
   if (logger.isInfoEnabled()) {
      logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
   }

   // 拿到 ControllerAdvice 标注的类
   List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
   AnnotationAwareOrderComparator.sort(adviceBeans);

   List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

   for (ControllerAdviceBean adviceBean : adviceBeans) {
      Class<?> beanType = adviceBean.getBeanType();
      if (beanType == null) {
         throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
      }
      // 设置 ModelAttribute 标注的方法
      Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
      if (!attrMethods.isEmpty()) {
         this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
         if (logger.isInfoEnabled()) {
            logger.info("Detected @ModelAttribute methods in " + adviceBean);
         }
      }
      // 设置 InitBinder 标注的方法
      Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
      if (!binderMethods.isEmpty()) {
         this.initBinderAdviceCache.put(adviceBean, binderMethods);
         if (logger.isInfoEnabled()) {
            logger.info("Detected @InitBinder methods in " + adviceBean);
         }
      }

      boolean isRequestBodyAdvice = RequestBodyAdvice.class.isAssignableFrom(beanType);
      boolean isResponseBodyAdvice = ResponseBodyAdvice.class.isAssignableFrom(beanType);
      if (isRequestBodyAdvice || isResponseBodyAdvice) {
         requestResponseBodyAdviceBeans.add(adviceBean);
         if (logger.isInfoEnabled()) {
            if (isRequestBodyAdvice) {
               logger.info("Detected RequestBodyAdvice bean in " + adviceBean);
            }
            else {
               logger.info("Detected ResponseBodyAdvice bean in " + adviceBean);
            }
         }
      }
   }

   if (!requestResponseBodyAdviceBeans.isEmpty()) {
      this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
   }
}

设置默认的 argumentResolvers

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
   List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

   // Annotation-based argument resolution
   resolvers.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 resolution
   resolvers.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());

   // Custom arguments
   if (getCustomArgumentResolvers() != null) {
      resolvers.addAll(getCustomArgumentResolvers());
   }

   // Catch-all
   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
   resolvers.add(new ServletModelAttributeMethodProcessor(true));

   return resolvers;
}

设置默认的 returnValueHandlers

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
   List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();

   // Single-purpose return value types
   handlers.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 types
   handlers.add(new ModelAttributeMethodProcessor(false));
   handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
         this.contentNegotiationManager, this.requestResponseBodyAdvice));

   // Multi-purpose return value types
   handlers.add(new ViewNameMethodReturnValueHandler());
   handlers.add(new MapMethodProcessor());

   // Custom return value types
   if (getCustomReturnValueHandlers() != null) {
      handlers.addAll(getCustomReturnValueHandlers());
   }

   // Catch-all
   if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
      handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
   }
   else {
      handlers.add(new ModelAttributeMethodProcessor(true));
   }

   return handlers;
}

总结

在RequestMappingHandlerAdapter初始化时,设置好 参数解析器HandlerMethodArgumentResolver、返回值解析器HandlerMethodReturnValueHandler、类型转换器DefaultFormattingConversionService

免安装版Notepad++终极配置:右键菜单+图标美化+多文件批量处理(2024新版) 本文详细介绍了如何为免安装版Notepad++进行终极配置,包括右键菜单添加、图标美化以及多文件批量处理功能。通过注册表编辑和高级定制,用户可以在便携版中实现与安装版相同的功能体验,同时保持系统整洁。特别适合开发者、系统管理员和效率追求者使用。 阅读详情

相关推荐

【计算机组成原理】实验4:单周期CPU(Verilog)中海大

【计算机组成原理】实验4:单周期CPU

m0_63023532的博客 3659

SpringMVC系列六:RequestMappingHandlerMapping的初始化

因为RequestMappingHandlerMapping实现InitializingBean接口所以在spring初始化的时候调用在RequestMappingHandlerMapping的afterPropertiesSet方法,并在其中设置 Method 与 RequestMappingInfo 的映射关系。设置请求 url 与 RequestMappingInfo 的映射关系,设置 RequestMappingInfo 与 HandlerMethod 的映射关系。解析映射关系初始化完成。

Running666的博客 504

SOC-ATF 安全启动BL2流程分析(2)

Bl2的启动流程与bl1类似,主要区别是bl2的初始化流程比bl1更简单,但其可能需要加载更多的镜像,如bl31、bl32和bl33。由于bl2可以运行于el3或s-el1,它们的入口函数和处理流程都有所区别,为了简化分析我们选取比较常见的s-el1方式,以下为其总体执行流程:上图仅供参考,实际看一下代码结构:上面截图展示了 链接汇编文件,bl2_el3.ld.S 是指bl2 运行于el3;bl2.ld.S 是实现bl2运行于s-el1 .

z20230508的博客 1387

【SpringMVC】| 一文带你搞定SpringMVC的@RequestMapping注解

一文带你搞定SpringMVC的@RequestMapping注解

m0_61933976的博客 1350

告别Vysor!用Scrcpy在Mac上无线投屏安卓手机(附魅族16th闪退修复实战)

本文详细介绍了如何在Mac上配置和使用开源投屏工具Scrcpy,实现安卓手机无线投屏的高效解决方案。从基础环境准备到高级功能调优,包括无线连接配置、输入控制增强、多设备管理和性能优化等实用技巧,特别针对魅族16th等机型的闪退问题提供了修复方案,帮助用户彻底告别Vysor等商业软件。

weixin_28712661的博客 393

PADS Layout中快速导入自定义元器件封装的实用技巧

本文详细介绍了在PADS Layout中高效导入自定义元器件封装的实用技巧。针对封装“找不到”、“对不上”、“导不进”三大痛点,系统梳理了从封装文件来源识别、库规划管理,到三种核心导入场景(从库文件添加、从其他设计借用、处理第三方格式)的完整操作流程,并提供了导入后的关键验证清单与常见问题排查方法,旨在帮助硬件工程师快速掌握这一提升设计效率的关键技能。

weixin_29302047的博客 375

springmvc源码学习(八)RequestMappingHandlerAdapter

目录前言一、getHandler( )二、使用步骤1.引入库2.读入数据总结 前言 。 前面分析过RequestMappingHandlerMapping的初始化过程,解析了@Controller等注解信息,将Controller访问路径与方法信息缓存起来,下面分析一下获取过程。 一、getHandler( ) (1) getHandler( ) 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。 二、使用步骤 1.引入库 代码如下(示例): import n..

码易的博客 2360

UE5Could not be compiled. Try rebuilding from source manually.

UE5Could not be compiled. Try rebuilding from source manually.

weixin_45417260的博客 2770

SpringMvc @Requestmapping参数配置

1) 普通path路径 @RequestMapping(value = "/foos") @ResponseBody public String getFoosBySimplePath() {     return "Get some Foos"; } 然后尝试用curl请求下 curl -i http://localhost:8080/spring-mvc/foos 2)

doutao6677的专栏 650

基于STM32F4的NRF24L01驱动程序

基于STM32F4xx的NRF24L01驱动程序 提示:硬件平台基于STM32F427VIT6、NRF24L01模块 文章目录基于STM32F4xx的NRF24L01驱动程序前言一、NRF24L01简单介绍1,什么是NRF24L012,NRF24L01通信方法3,NRF24L01通信原理4,地址分配&通道分配问题二、STM32CubeMX配置三、添加底层文件1,添加.c/.h文件到工程中2,使用说明四,下载 前言 提示:本例程采用STM32CubeMX配置底层,采用硬件SPI方式驱动NRF24

qq_43603289的博客 2812

COMSOL有限元仿真深度指南:连接薄结构与实体结构(I)

COMSOL有限元仿真深度指南:如何在结构力学仿真中连接薄结构与实体结构?

忘了面孔的Batou 1万+

SpringMVC-RequestMappingHandlerAdapter

本文分析了SpringMVC框架中RequestMappingHandlerAdapter的工作原理,主要包括三个核心功能:参数解析、执行处理逻辑和返回值处理。在参数解析阶段,通过HandlerMethodArgumentResolver解析@RequestParam、@PathVariable和@RequestBody等注解修饰的参数;执行阶段通过反射方式调用handler方法;返回值处理阶段则使用HandlerMethodReturnValueHandler处理不同类型的返回值,包括ResponseEn

384

SPI为什么不需要加上拉电阻

大家好,我是记得诚。I2C因为其开漏的结构,无法输出高电平,所以外部加上拉电阻。我们在使用SPI的时候,发现是不需要加上拉电阻的。主要因为SPI多为推挽的结构,推挽电路,高低电平都可以输出,所以外部不需要加上拉电阻。推挽电路可以用2个三极管或者2个MOS管搭建而成。

记得诚 2618

Spring MVC之RequestMappingHandlerAdapter初始化

RequestMappingHandlerAdapter基于注解的处理器适配器,目的是用来执行handler,同时返回modelAndView给前端控制器,这块个人感觉是spring mvc的核心了,所以我会详细一些记录。本篇文章先记录他初始化都做了什么。先上类图: 通过类图可以看到,实现了InitializingBean接口,所以入口的方法就是afterPropertiesSe...

dhemz20268的专栏 223

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

SpringMVC RequestMappingHandlerAdapter源码解析

SpringMVC RequestMappingHandlerAdapter 他是干什么初始化调用过程小结 他是干什么 RequestMappingHandlerAdapter处理执行我们最常用的@requestMapping 的方法,也是目前mvc提供的最常用最复杂的 handlerAdapter相对于其他的。他功能很简单:通过反射执行我们标记 @requestMapping 的方法。但是他复...

qq_33221085的博客 510

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

【Spring】抽丝剥茧SpringMVC-RequestMappingHandlerAdapter

request经过HandlerMapping找到了对应的Handler。但是要执行Handler,还需要从request中提取handler需要的参数,handler执行后返回值也需要经过处理才能作为response返回。这些操作都是由MVC另一个核心组件-HandlerAdapter完成。 HandlerAdapter核心事情主要有3件:参数预处理、调用Handler、返回值处理。 参数预处理是从request的body、query、header等解析并转换为Handler对应的参数...

beFocused的博客 474

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

RequestMappingHandlerAdapter处理流程

DispatcherServlet 通过 HandlerMapping 匹配完各种条件后,终于找到目标处理器 handler了。但是 handler 是个 Object,它可能是 Spring MVC 内置的 handler,也可能是你自定义的 handler,总之 DispatcherServlet 并不认识它,没法指挥它干活。这个时候,就需要依赖 HandlerAdapter 组件了。它是处理器适配器,顾名思义它是协调 handler 干活的角色,它肯定认识它能指挥的 handler。

程序员小潘 1601

探索SpringMVC-HandlerAdapter之RequestMappingHandlerAdapter

在前面理解了参数解析、返回值处理,我们来了解整个RequstMappingHandlerAdapter是怎么设计和串联的。

Evan_L的博客 948

SpringMVC之RequestMappingHandlerAdapter

下面是HandlerAdapter的接口定义: public interface HandlerAdapter { /** * Given a handler instance, return whether or not this {@code HandlerAdapter} * can support it. Typical HandlerAdapters will base th...

m0_37343985的博客 844

享读SpringMVC源码4-感谢RequestMappingHandlerAdapter

当我们享受参数接收便利的同时,不得不不感谢RequestMappingHandlerAdapter背后所做的工作

2017年 382

SpringMVC源码解析之RequestMappingHandlerAdapter

RequestMappingHandlerAdapter含有大量的web基础组件协助完成一整个请求的调度、处理 RequestMappingHandlerAdapter 适配@RequestMapping注解标注的Handler(HandlerMethod类型) Spring3.1新增的一个适配器类,用于数据绑定、数据转换、数据校验、内容协商 因为有了它的存在,使得开发者几乎可以忘掉原生的Servlet API Spring 5.0在把Servlet容器从必选项变成可选项后,即使切换了web容器(比如换成j

JavaEdge全是干货的技术号 1737

SpringMVC之分析RequestMappingHandlerAdapter(一)

RequestMappingHandlerAdapter请求映射处理适配器,在SpringMVC中它是一个非常重要的类,对请求处理方法的调用主要是通过这个类来完成的(这段代码mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)。下面我们就简单的分析一下这个类。首先我们先看一下它的UML类图结构:

398701344努力加油! 1万+

springmvc RequestMappingHandlerAdapter初始化详解

我们来看一下RequestMappingHandlerAdapter初始化时做了什么? initControllerAdviceCache()方法是处理注解@ControllerAdvice的,此时我们暂且不关注 这个就比较关键了,注解了很多参数解析器,后文详解#1 返回用于@initbinder方法的参数解析器列表,包括内置的和自定义的解析器。注册步骤和上一步如出一...

359

【Spring高级】RequestMappingHandlerMapping和RequestMappingHandlerAdapter

Spring高级:RequestMappingHandlerMapping和RequestMappingHandlerAdapter

qq_43745578的博客 1314

RequestMappingHandlerAdapter

和是 Spring MVC 中非常重要的两个组件,它们在处理 HTTP 请求时扮演着不同的角色。

ruangongtaotao的专栏 555

springmvc组件HandlerAdapter源码分析-RequestMappingHandlerAdapter

1.springmvc中RequestMappingHandlerAdapter继承体系 2.概述 首先,RequestMappingHandlerAdapter实现了InitializingBean接口, bean初始化是会调用afterPropertiesSet方法来处理加了ControllerAdvice注解的类 加载HandlerMethodArgumentResolver参数解析器处理参数 加载处理InitBinder的HandlerMethodArgumentResolver参..

qq_39482039的博客 427
上一篇: SpringMVC系列六:RequestMappingHandlerMapping的初始化
下一篇: Spring结合Tomcat解决Jsp乱码问题
技术爱好者666
博客等级 码龄9年 4粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值