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

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

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

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

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

先说结论,分两种情况。

情况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 实现感兴趣,也可以看我的博客或者和我私聊讨论,有帮助麻烦采纳哦!