SpringMVC源码分析-HandlerAdapter(8)-HandlerMethodArgumentResolver组件分析

HandlerMethodArgumentResolver

HandlerMethodArgumentResolver用来为处理器解析参数
主要在InvocableHandlerMethod中使用
由于每个Resolver对应一种类型的参数,所以有很多实现类

Resolver

HandlerMethodArgumentResolverComposite

其中HandlerMethodArgumentResolverComposite较为特殊,从命名来看这是一个组合模式
它本身并不像其他子类一样可以解析具体参数,而是对多个解析器进行封装
解析参数时,调用封装在其中的解析器进行具体解析

1)HandlerMethodArgumentResolver接口:

public interface HandlerMethodArgumentResolver {
    // 是否支持解析传入的参数
    boolean supportsParameter(MethodParameter parameter);
    // 具体解析逻辑
    Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

2)从继承关系可以发现HandlerMethodArgumentResolver的实现类一般有两种命名方式:

1,XXXMethodArgumentResolver
    参数解析器
2,XXXMethodProcessor
    不仅可以解析参数,
    还可以处理相应类型的返回值(实现了HandlerMethodReturnValueHandler)

3)还有一组Adapter类,用于兼容WebArgumentResolver类型的参数解析器的适配器

这里写图片描述


各种解析器作用

各种解析器的作用:


常用解析器分析

1,ModelMethodProcessor

Model类型参数解析器
XXXProcessor命名,既可以解析参数,也可以处理返回值

ModelMethodProcessor源码:

public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {

    // 支持解析Model类型的参数
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return Model.class.isAssignableFrom(parameter.getParameterType());
    }

    // 直接返回mavContainer中的Model
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        return mavContainer.getModel();
    }

    // 支持解析Model类型的返回值
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return Model.class.isAssignableFrom(returnType.getParameterType());
    }

    // 返回值不为null且是Model类型,将返回值加入到Model中,否则抛出异常
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        if (returnValue == null) {
            return;
        }
        else if (returnValue instanceof Model) {
            mavContainer.addAllAttributes(((Model) returnValue).asMap());
        }
        else {
            // should not happen
            throw new UnsupportedOperationException("Unexpected return type: " +
                    returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
        }
    }

}
分别实现了参数和返回值支持类型和具体处理逻辑
支出Model类型的参数解析和返回值处理
参数解析:直接返回mavContainer中的Model
返回值处理:返回值不为null且是Model类型,将返回值加入到Model中,否则抛出异常

2,PathVariableMethodArgumentResolver

PathVariableMethodArgumentResolver

用于解析url路径中的值
继承自AbstractNamedValueMethodArgumentResolver

AbstractNamedValueMethodArgumentResolver

NamedValue

从继承关系可以看到:
    多种解析器都继承自AbstractNamedValueMethodArgumentResolver

AbstractNamedValueMethodArgumentResolver是一个模板模式

没有实现supportsParameter方法,只实现了resolveArgument方法

AbstractNamedValueMethodArgumentResolver#resolveArgument参数的具体处理逻辑:

@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

    // 创建 MethodParameter 对应的 NamedValueInfo
    NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
    MethodParameter nestedParameter = parameter.nestedIfOptional();

    // 因为此时的 name 可能还是被 ${} 符号包裹, 
    // 则通过 BeanExpressionResolver 来进行解析
    Object resolvedName = resolveStringValue(namedValueInfo.name);
    if (resolvedName == null) {
        throw new IllegalArgumentException(
                "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
    }

    // 具体解析参数的方法,模板方法,子类实现
    Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
    // 如果没有解析到参数
    if (arg == null) {
        // namedValueInfo是否有默认值
        if (namedValueInfo.defaultValue != null) {
            // 解析参数
            arg = resolveStringValue(namedValueInfo.defaultValue);
        }
        // 没有默认值且required=true
        else if (namedValueInfo.required && !nestedParameter.isOptional()) {
            //参数缺失处理,抛出相应类型异常
            handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
        }
        // null值处理
        arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
    }
    else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
        arg = resolveStringValue(namedValueInfo.defaultValue);
    }

    // 如果binderFactory不为空,则用binderFactory创建binder
    // 如果需要转换,则转换解析出来的参数
    if (binderFactory != null) {
        WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
        try {
            arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
        }
        catch (ConversionNotSupportedException ex) {
            throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                    namedValueInfo.name, parameter, ex.getCause());
        }
        catch (TypeMismatchException ex) {
            throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                    namedValueInfo.name, parameter, ex.getCause());

        }
    }

    // 对解析出来的参数进行后置处理
    handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

    return arg;
}

// 具体解析参数的方法,模板方法,子类实现
protected abstract Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)
            throws Exception;
首先根据 MethodParameter 创建了 NamedValueInfo
之后将相关参数传入模板方法resolveName由子类进行具体解析
最后对解析返回的结果进行处理

NamedValueInfo是一个内部类

protected static class NamedValueInfo {

    private final String name;// 参数名
    private final boolean required;// 是否必输
    private final String defaultValue;// 默认值

    public NamedValueInfo(String name, boolean required, String defaultValue) {
        this.name = name;
        this.required = required;
        this.defaultValue = defaultValue;
    }
}
resolveName解析完成后,判断解析结果是否为null或空串
    是null或空串,判断NamedValueInfo是否包含默认值
        包含,调用resolveStringValue传入
    不是null或空串,

猜你喜欢

转载自blog.csdn.net/abap_brave/article/details/80968683