HandlerMethodArgumentResolver(三):基于HttpMessageConverter消息转换器的参数解析器【享学Spring MVC】(下)

简介: HandlerMethodArgumentResolver(三):基于HttpMessageConverter消息转换器的参数解析器【享学Spring MVC】(下)

Spring MVC参数处理器的注册与顺序


到这里,一个不落的把Spring MVC内置提供的参数处理器ArgumentResolver说了个遍。

前面我有提到过:参数处理对处理器的顺序是敏感的,因此我们需要关注Spring MVC最终的执行顺序,这时候我们的聚合容器HandlerMethodArgumentResolverComposite就出场了:

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
  private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
  // 具有缓存
  private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<>(256); 
  ...
  // @since 4.3  木有任何地方调用
  public void clear() {
    this.argumentResolvers.clear();
  }
  // getArgumentResolver()方法是本文的核心
  @Override
  public boolean supportsParameter(MethodParameter parameter) {
    return getArgumentResolver(parameter) != null;
  }
  @Override
  @Nullable
  public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    // 这里是关键:每个参数最多只会被一个处理器处理
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) {
      throw new IllegalArgumentException("Unsupported parameter type [" + parameter.getParameterType().getName() + "]." + " supportsParameter should be called first.");
    }
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
  }
  ... 
  // 这块逻辑保证了每个parameter参数最多只会被一个处理器处理
  // 这个从缓存的数据结构中也能够看出来的
  @Nullable
  private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
      for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
        if (methodArgumentResolver.supportsParameter(parameter)) {
          result = methodArgumentResolver;
          this.argumentResolverCache.put(parameter, result);
          break;
        }
      }
    }
    return result;
  }
}


缺省情况Spring MVC注册的处理器(顺序)如下:

image.png

它初始化处的代码如下:


RequestMappingHandlerAdapter:
  @Override
  public void afterPropertiesSet() {
    ...
    // 26个,详见方法getDefaultArgumentResolvers
    if (this.argumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
      this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 12个  详见方法getDefaultInitBinderArgumentResolvers
    if (this.initBinderArgumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
      this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    ...
  }


注意:这里面initBinderArgumentResolvers最终只会有12个处理器,因为它的注册方法如下截图(也是这个顺序):


image.png


前面有提到过说标注有@InitBInder注解里也可以写很多类型的参数,但因为它只会有12个处理器,所以有些参数它是不能写的(比如@RequestBody、Errors等等这种都是不能写的),不用一一枚举,做到心中有数就成。


总结


本文介绍的处理内容,其实还是比较重要的,因为它和消息转换器HttpMessageConverter有关,毕竟它是我们目前主流的使用方式,希望可以帮助到大家理解。

这里可以提前预告一下:下篇文章将非常重要,因为我将结合实际场景,演示一个我们通过自定义HandlerMethodArgumentResolver实现的特殊场景的解决方案,非常的优雅和值得推广,有兴趣者可持续关注



相关文章
|
22天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
9天前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
16天前
|
JSON API 数据格式
requests库中json参数与data参数使用方法的深入解析
选择 `data`或 `json`取决于你的具体需求,以及服务器端期望接收的数据格式。
64 2
|
10天前
|
Java Spring
spring boot 启动项目参数的设定
spring boot 启动项目参数的设定
|
2月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
135 0
|
2月前
|
存储 Go UED
精通Go语言的命令行参数解析
【8月更文挑战第31天】
25 0
|
9天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
Java Spring 前端开发
spring 3.2 自定义参数绑定--日期格式转换器
springmvc配置文件 &lt;!-- 代替org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter --&gt;
2428 0
|
2月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
3月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。

推荐镜像

更多
下一篇
无影云桌面