a_wing啊 2021-10-07 18:50 采纳率: 50%
浏览 325
已结题

在SpringBoot中,Controller的参数中有Map接口类型的,请问他的实现类是什么?

突发奇想,在SpringBoot中,Controller的参数中有Map接口类型的

    @GetMapping("/common")
    public HttpResult testCommonGet(Map<String,String> map){

        return  HttpResult.success("common测试get");
    }

像这里的map,声明是Map接口,那他的实现类是什么?
如果改为HashMap类型,有什么优缺点吗?

  • 写回答

1条回答 默认 最新

  • 大鹏cool Java领域优质创作者 2021-10-07 19:32
    关注

    先说结论,分两种情况。

    情况1:不带注解的 Controller 方法 Map 参数类型,Map 的实现类是 Spring 提供的 BindingAwareModelMap,HashMap 完全可以替换 Map。需要注意的是此时 Map 不是用来接收请求参数的,而是作为 view 中使用的一个 model,用来填充 view ,如将 jsp 页面中的变量替换为具体的值。

    情况2:带 @RequestBody 注解将 Map 作为请求体,Map 的实现类是 LinkedHashMap,HashMap 可以替换 Map。

    情况1分析:Spring Controller 中的方法参数类型多种多样,Spring 调用 Controller 方法时必须保证能够为每个参数提供对应的值,Spring 的解决方案是提供一个通用的接口 HandlerMethodArgumentResolver,不同的参数类型由不同的实现处理。

    HandlerMethodArgumentResolver 接口定义如下。

    public interface HandlerMethodArgumentResolver {
    
        boolean supportsParameter(MethodParameter parameter);
    
        @Nullable
        Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                               NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
    
    }
    

    如果 HandlerMethodArgumentResolver 的实现支持给定的参数类型,就会将参数类型解析为值,Spring 解析不带注解的 Map 参数类型使用的是 MapMethodProcessor。源码如下。

    public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
        public MapMethodProcessor() {
        }
    
        public boolean supportsParameter(MethodParameter parameter) {
            return Map.class.isAssignableFrom(parameter.getParameterType()) && parameter.getParameterAnnotations().length == 0;
        }
    
        @Nullable
        public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
            Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
            return mavContainer.getModel();
        }
    
        public boolean supportsReturnType(MethodParameter returnType) {
            return Map.class.isAssignableFrom(returnType.getParameterType());
        }
    
        public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
            if (returnValue instanceof Map) {
                mavContainer.addAllAttributes((Map)returnValue);
            } else if (returnValue != null) {
                throw new UnsupportedOperationException("Unexpected return type [" + returnType.getParameterType().getName() + "] in method: " + returnType.getMethod());
            }
    
        }
    }
    

    可以看到,只要是 Map 类型参数,Spring 就会调用 ModelAndViewContainer#getModel 获取值,相关源码如下。

    public class ModelAndViewContainer {
        private final ModelMap defaultModel = new BindingAwareModelMap();
    
        public ModelMap getModel() {
            if (this.useDefaultModel()) {
                return this.defaultModel;
            } else {
                if (this.redirectModel == null) {
                    this.redirectModel = new ModelMap();
                }
    
                return this.redirectModel;
            }
        }
    
    }
    

    最终使用的就是 ModelAndViewContainer 内部的 BindingAwareModelMap 实例,这个类实现了 LinkedHashMap,这也意味着如果你使用 TreeMap 作为参数,由于类型不匹配将会导致程序报错。

    情况2分析:带 @RequestBody 的参数,由 RequestResponseBodyMethodProcessor 解析,默认情况下交由 MappingJackson2HttpMessageConverter 实例化参数,如果是 Map 实例化出来的是 HashMap 类型,这块源码内容较多,可自己尝试分析。

    最后如果你对 Spring 实现感兴趣,也可以看我的博客或者和我私聊讨论,有帮助麻烦采纳哦!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 10月17日
  • 已采纳回答 10月9日
  • 修改了问题 10月7日
  • 创建了问题 10月7日

悬赏问题

  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型