SpringMVC源码分析(八)--参数解析器

1.参数解析器介绍

参数解析器用于解析Handler方法参数,例如经常看到Handler方法签名中有HttpServletRequest、HttpServletResponse等对象,还有请求参数中有@RequestBody、@PathVariable等注解修饰的对象,这些对象都是经过参数解析器解析后注入的

SpringMVC中默认的参数解析器见RequestMappingHandlerAdapter#getDefaultArgumentResolvers

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

    // 基于注解的参数解析器
    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());
 
    // 基于类型的参数解析器
    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());

    // 添加自定义参数解析器
    if (getCustomArgumentResolvers() != null) {
       resolvers.addAll(getCustomArgumentResolvers());
    }

    // 能够处理所有场景
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    resolvers.add(new ServletModelAttributeMethodProcessor(true));

    return resolvers;
}

这些参数解析器会被封装到HandlerMethodArgumentResolverComposite中,处理参数时,会按照加入的顺序依次调用每个参数解析器执行解析任务,直到其中某个参数解析器能够解析此参数,则返回参数解析结果

2.自定义参数解析器

在某些场景下,我们可以自定义参数解析器,将某些数据通过参数传递到Handler方法中,例如在支付的场景中,我想要将渠道信息从请求头header中设置到Handler方法的参数中,这时我们可以自定义注解,然后再自定义参数解析器实现HandlerMethodArgumentResolver接口,将渠道的值传递到Handler方法中,示例如下:

1)创建Channel注解及自定义参数解析器

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Channel {
}

public class ChannelArgumentResolver implements HandlerMethodArgumentResolver {
    // 是否支持解析此参数
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        Channel channel = methodParameter.getParameterAnnotation(Channel.class);
        return channel != null;
    }
    
    // 解析参数
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
                                  NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        String channel = nativeWebRequest.getHeader("x-chnl");
        return channel;
    }
}

2)在配置类中加入自定义参数解析器

这样初始HandlerAdapter时,就会将自定义的参数解析器加入到参数解析器集合中

@Configuration
@ComponentScan
public class WebConfig {
    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean servletRegistrationBean(DispatcherServlet dispatcherServlet) {
        DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        registrationBean.setLoadOnStartup(1);
        return registrationBean;
    }

    @Bean
    public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        MyRequestMappingHandlerAdapter handlerAdapter = new MyRequestMappingHandlerAdapter();
        // 添加自定义参数解析器
        handlerAdapter.setCustomArgumentResolvers(Arrays.asList(new ChannelArgumentResolver()));
        return handlerAdapter;
    }
}

3)添加控制器

@RestController
public class Controller {
    @GetMapping("/test")
    public void test(@Channel String channel) {
        System.out.println("渠道:" + channel);
    }
}

4)添加启动类

public class Test {
    public static void main(String[] args) {
        AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }
}

启动程序后使用postman调用http://127.0.0.1:8080/test,并在请求头中加入x-chnl=google,就能够打印出渠道信息,说明自定义参数解析器能够将渠道信息设置到test方法的参数中

3.参数解析器原理

参数解析器都实现了HandlerMethodArgumentResolver接口,它提供了如下两个方法

public interface HandlerMethodArgumentResolver {
    // 是否支持解析此参数
    boolean supportsParameter(MethodParameter parameter);
    
    // 解析参数
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, 
                            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}

接下来分析下常用的参数解析器的解析原理

3.1 RequestParamMethodArgumentResolver

3.1.1 RequestParamMethodArgumentResolver支持的参数类型

public boolean supportsParameter(MethodParameter parameter) {
    // 情况一:如果参数上有@RequestParam注解
    if (parameter.hasParameterAnnotation(RequestParam.class)) {
        // 如果有@RequestParam注解,并且参数类型是Map的子类
        if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
            RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
            // @RequestParam中的name属性如果有值,则支持
            return (requestParam != null && StringUtils.hasText(requestParam.name()));
        }
        // 如果不是Map的子类则支持
        else {
            return true;
        }
    }
    // 情况二:如果参数上没有@RequestParam注解
    else {
        // 如果参数上有@RequestPart,则不处理
        if (parameter.hasParameterAnnotation(RequestPart.class)) {
            return false;
        }
        parameter = parameter.nestedIfOptional();
        // 如果参数类型是Multipart,则支持
        if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
            return true;
        }
        // 构造时需要传入此参数,如果为true,则判断参数类型是不是简单类型
        // 这里的简单类型指的是Enum、CharSequence、Number、Date、Temporal、URI、URL、Locale及Class
        else if (this.useDefaultResolution) {
            return BeanUtils.isSimpleProperty(parameter.getNestedParameterType());
        }
        // 如果不满足上面所有的条件则不支持
        else {
            return false;
        }
    }
}

总结一下,RequestParamMethodArgumentResolver存在两种使用场景:

  • 如果有@RequestParam注解,只要参数不是Map的子类且没有指定@RequestParam注解的name属性,其他情况都支持
  • 如果没有@RequestParam注解,能支持解析Multipart类型,如果传入的useDefaultResolution为true的话,还能够支持解析一些简单类型

3.1.2 RequestParamMethodArgumentResolver解析流程

RequestParamMethodArgumentResolver继承自AbstractNamedValueMethodArgumentResolver,解析方法定义在父类中,源码见AbstractNamedValueMethodArgumentResolver#resolveArgument

public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
       NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    // 1.获取参数名称和参数值信息
    NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
    MethodParameter nestedParameter = parameter.nestedIfOptional();

    // 2.解析参数名称占位符及表达式
    Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
    if (resolvedName == null) {
       throw new IllegalArgumentException(
             "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
    }

    // 3.抽象方法子类实现,从请求中解析名称对应的数据
    Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
    if (arg == null) {
       if (namedValueInfo.defaultValue != null) {
          arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
       }
       else if (namedValueInfo.required && !nestedParameter.isOptional()) {
          handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
       }
       arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
    }
    else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
       arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
    }

    if (binderFactory != null) {
        // 通过数据绑定工厂创建数据绑定器
       WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
       try {
           // 4.使用数据绑定器转换成方法参数类型
          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());
       }
    }

    // 5.抽象方法子类实现,处理解析后的值
    handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);

    return arg;
}

AbstractNamedValueMethodArgumentResolver中解析参数分为如下5步:

1)获取参数名称和参数值信息

private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
    NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
    if (namedValueInfo == null) {
        // 1.1 创建NamedValueInfo对象,抽象方法子类实现
        namedValueInfo = createNamedValueInfo(parameter);
        // 1.2 更新NamedValueInfo对象属性
        namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
        this.namedValueInfoCache.put(parameter, namedValueInfo);
    }
    return namedValueInfo;
    }

private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValueInfo info) {
    String name = info.name;
    if (info.name.isEmpty()) {
        // 如果name为空,使用参数名称解析器解析参数名作为name
        // 这就是为什么@RequestParm可以不写name属性的原因,它会自动匹配参数名称
        name = parameter.getParameterName();
        if (name == null) {
        throw new IllegalArgumentException(
            "Name for argument of type [" + parameter.getNestedParameterType().getName() +
                "] not specified, and parameter name information not found in class file either.");
        }
    }
    String defaultValue = (ValueConstants.DEFAULT_NONE.equals(info.defaultValue) ? null : info.defaultValue);
    return new NamedValueInfo(name, info.required, defaultValue);
}

// MethodParameter#getParameterName
public String getParameterName() {
    if (this.parameterIndex < 0) {
       return null;
    }
    ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer;
    if (discoverer != null) {
       String[] parameterNames = null;
       if (this.executable instanceof Method) {
           // 使用参数解析器解析方法参数
          parameterNames = discoverer.getParameterNames((Method) this.executable);
       }
       else if (this.executable instanceof Constructor) {
          parameterNames = discoverer.getParameterNames((Constructor<?>) this.executable);
       }
       if (parameterNames != null) {
          this.parameterName = parameterNames[this.parameterIndex];
       }
       this.parameterNameDiscoverer = null;
    }
    return this.parameterName;
}

// RequestParamMethodArgumentResolver#createNamedValueInfo
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
    RequestParam ann = parameter.getParameterAnnotation(RequestParam.class);
    // 创建NamedValueInfo,其中name为@RequestParam注解中的name值,require是@RequestParam注解中的require值,defaultValue为默认值
    return (ann != null ? new RequestParamNamedValueInfo(ann) : new RequestParamNamedValueInfo());
}

// RequestParamMethodArgumentResolver.RequestParamNamedValueInfo
private static class RequestParamNamedValueInfo extends NamedValueInfo {
    public RequestParamNamedValueInfo() {
       super("", false, ValueConstants.DEFAULT_NONE);
    }

    public RequestParamNamedValueInfo(RequestParam annotation) {
       super(annotation.name(), annotation.required(), annotation.defaultValue());
    }
}

在获取参数名称时,如果@RequestParam注解中没有指定name属性,则会通过参数名称解析器解析方法参数名称作为name,参数名称解析器可参考SpringMVC源码分析(六)--参数名称解析器-CSDN博客

2)解析参数名称表达式

@RequestParam注解中name属性有可能设置为SpEL表达式,例如:@RequestParam(name="${test.name}"),

private Object resolveEmbeddedValuesAndExpressions(String value) {
    if (this.configurableBeanFactory == null || this.expressionContext == null) {
        return value;
    }
    // 解析占位符
    String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(value);
    BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver();
    if (exprResolver == null) {
        return value;
    }
    // 解析表达式
    return exprResolver.evaluate(placeholdersResolved, this.expressionContext);
}

3)从请求中解析名称对应的数据

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
    
    if (servletRequest != null) {
        // 解析multipart类型的请求参数
        Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);
        if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
            return mpArg;
        }
    }
    
    Object arg = null;
    // 处理MultipartRequest类型的请求
    MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
    if (multipartRequest != null) {
        List<MultipartFile> files = multipartRequest.getFiles(name);
        if (!files.isEmpty()) {
            arg = (files.size() == 1 ? files.get(0) : files);
        }
    }
    if (arg == null) {
        // 根据名称从请求中获取参数
        String[] paramValues = request.getParameterValues(name);
        if (paramValues != null) {
            arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
        }
    }
    return arg;
}

4)使用数据绑定器转换成方法参数类型

通过DataBinder将从请求中获取的数据转换为Handler方法的参数类型,这部分原理可参考SpringMVC源码分析(七)--数据绑定工厂-CSDN博客

5)处理解析后值

默认解析器中仅PathVariableMethodArgumentResolver重写了此方法

3.2 PathVariableMethodArgumentResolver

3.2.1 PathVariableMethodArgumentResolver支持的参数类型

public boolean supportsParameter(MethodParameter parameter) {
    // 参数上必须有@PathVariable注解
    if (!parameter.hasParameterAnnotation(PathVariable.class)) {
       return false;
    }
    if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
       PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
       // 如果参数类型是Map,@PathVariable注解中value必须有值
       return (pathVariable != null && StringUtils.hasText(pathVariable.value()));
    }
    return true;
}

从源码可知,PathVariableMethodArgumentResolver能解析带有@PathVariable注解的参数

3.2.2 PathVariableMethodArgumentResolver解析流程

PathVariableMethodArgumentResolver也继承自AbstractNamedValueMethodArgumentResolver,解析方法定义在父类中,参考上文RequestParamMethodArgumentResolver的解析流程,此处我们重点关注下PathVariableMethodArgumentResolver重写的方法

1)创建NamedValueInfo:从@PathVariable注解属性中获取

protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
    PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
    Assert.state(ann != null, "No PathVariable annotation");
    return new PathVariableNamedValueInfo(ann);
}

private static class PathVariableNamedValueInfo extends NamedValueInfo {
    public PathVariableNamedValueInfo(PathVariable annotation) {
        super(annotation.name(), annotation.required(), ValueConstants.DEFAULT_NONE);
    }
}

2)从请求中解析名称对应的数据

protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
    // 从请求中获取到路径占位符与实际值的映射关系
    Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
          HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
    // 获取路径上实际传入的值
    return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
}

3)处理解析后值

protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
       @Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {
    String key = View.PATH_VARIABLES;
    int scope = RequestAttributes.SCOPE_REQUEST;
    Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(key, scope);
    if (pathVars == null) {
       pathVars = new HashMap<>();
       // 向Request域中设置属性,即路径上占位符-转换类型后的实际值的映射关系
       request.setAttribute(key, pathVars, scope);
    }
    pathVars.put(name, arg);
}

3.3 RequestResponseBodyMethodProcessor

3.3.1 RequestResponseBodyMethodProcessor支持的参数类型

public boolean supportsParameter(MethodParameter parameter) {
    // 参数上有@RequestBody注解
    return parameter.hasParameterAnnotation(RequestBody.class);
}

3.3.2 RequestResponseBodyMethodProcessor解析逻辑

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
       NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    parameter = parameter.nestedIfOptional();
    // 使用消息转换器将请求body中json数据转换为对象
    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
    String name = Conventions.getVariableNameForParameter(parameter);

    if (binderFactory != null) {
       WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
       if (arg != null) {
          validateIfApplicable(binder, parameter);
          if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
             throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
          }
       }
       if (mavContainer != null) {
          mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
       }
    }

    // 如果参数是Optional类型,则将对象封装成Optional对象
    return adaptArgumentIfNecessary(arg, parameter);
}

protected Object adaptArgumentIfNecessary(@Nullable Object arg, MethodParameter parameter) {
    if (parameter.getParameterType() == Optional.class) {
       if (arg == null || (arg instanceof Collection && ((Collection) arg).isEmpty()) ||
             (arg instanceof Object[] && ((Object[]) arg).length == 0)) {
          return Optional.empty();
       }
       else {
          return Optional.of(arg);
       }
    }
    return arg;
}

RequestResponseBodyMethodProcessor解析时将请求体中数据通过MessageConverter转成目标对象

3.4 ServletRequestMethodArgumentResolver

3.4.1 ServletRequestMethodArgumentResolver支持的参数类型

public boolean supportsParameter(MethodParameter parameter) {
    Class<?> paramType = parameter.getParameterType();
    return (WebRequest.class.isAssignableFrom(paramType) ||
          ServletRequest.class.isAssignableFrom(paramType) ||
          MultipartRequest.class.isAssignableFrom(paramType) ||
          HttpSession.class.isAssignableFrom(paramType) ||
          (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) ||
          Principal.class.isAssignableFrom(paramType) ||
          InputStream.class.isAssignableFrom(paramType) ||
          Reader.class.isAssignableFrom(paramType) ||
          HttpMethod.class == paramType ||
          Locale.class == paramType ||
          TimeZone.class == paramType ||
          ZoneId.class == paramType);
}

A.isAssignableFrom(B)用于判断B类型是不是A类型或其子类型

因此,ServletRequestMethodArgumentResolver能支持解析的参数类型有WebRequest、ServletRequest、MultipartRequest、HttpSession、PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone及ZoneId

3.4.2 ServletRequestMethodArgumentResolver具体解析逻辑

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
       NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    Class<?> paramType = parameter.getParameterType();

    // 处理WebRequest、NativeWebRequest及ServletWebRequest
    if (WebRequest.class.isAssignableFrom(paramType)) {
       if (!paramType.isInstance(webRequest)) {
          throw new IllegalStateException(
                "Current request is not of type [" + paramType.getName() + "]: " + webRequest);
       }
       return webRequest;
    }

    // 处理ServletRequest、HttpServletRequest、MultipartRequest及MultipartHttpServletRequest
    if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) {
       return resolveNativeRequest(webRequest, paramType);
    }

    // 获取HttpServletRequest,处理其他支持的类型
    return resolveArgument(paramType, resolveNativeRequest(webRequest, HttpServletRequest.class));
}

private <T> T resolveNativeRequest(NativeWebRequest webRequest, Class<T> requiredType) {
    T nativeRequest = webRequest.getNativeRequest(requiredType);
    if (nativeRequest == null) {
       throw new IllegalStateException(
             "Current request is not of type [" + requiredType.getName() + "]: " + webRequest);
    }
    return nativeRequest;
}

private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {
    // 从请求中获取HttpSession
    if (HttpSession.class.isAssignableFrom(paramType)) {
       HttpSession session = request.getSession();
       if (session != null && !paramType.isInstance(session)) {
          throw new IllegalStateException(
                "Current session is not of type [" + paramType.getName() + "]: " + session);
       }
       return session;
    }
    // 从请求中获取PushBuilder
    else if (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) {
       return PushBuilderDelegate.resolvePushBuilder(request, paramType);
    }
    // 从请求中获取InputStream
    else if (InputStream.class.isAssignableFrom(paramType)) {
       InputStream inputStream = request.getInputStream();
       if (inputStream != null && !paramType.isInstance(inputStream)) {
          throw new IllegalStateException(
                "Request input stream is not of type [" + paramType.getName() + "]: " + inputStream);
       }
       return inputStream;
    }
    // 从请求中获取Reader
    else if (Reader.class.isAssignableFrom(paramType)) {
       Reader reader = request.getReader();
       if (reader != null && !paramType.isInstance(reader)) {
          throw new IllegalStateException(
                "Request body reader is not of type [" + paramType.getName() + "]: " + reader);
       }
       return reader;
    }
    // 从请求中获取Principal
    else if (Principal.class.isAssignableFrom(paramType)) {
       Principal userPrincipal = request.getUserPrincipal();
       if (userPrincipal != null && !paramType.isInstance(userPrincipal)) {
          throw new IllegalStateException(
                "Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal);
       }
       return userPrincipal;
    }
    // 从请求中获取HttpMethod
    else if (HttpMethod.class == paramType) {
       return HttpMethod.resolve(request.getMethod());
    }
    // 从请求中获取Locale
    else if (Locale.class == paramType) {
       return RequestContextUtils.getLocale(request);
    }
    // 从请求中获取TimeZone
    else if (TimeZone.class == paramType) {
       TimeZone timeZone = RequestContextUtils.getTimeZone(request);
       return (timeZone != null ? timeZone : TimeZone.getDefault());
    }
    // 从请求中获取ZoneId
    else if (ZoneId.class == paramType) {
       TimeZone timeZone = RequestContextUtils.getTimeZone(request);
       return (timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault());
    }

    throw new UnsupportedOperationException("Unknown parameter type: " + paramType.getName());
}

3.5 ServletResponseMethodArgumentResolver

3.5.1 ServletResponseMethodArgumentResolver能支持的参数类型

public boolean supportsParameter(MethodParameter parameter) {
    Class<?> paramType = parameter.getParameterType();
    return (ServletResponse.class.isAssignableFrom(paramType) ||
          OutputStream.class.isAssignableFrom(paramType) ||
          Writer.class.isAssignableFrom(paramType));
}

从源码可知,ServletResponseMethodArgumentResolver能支持解析的参数类型有ServletResponse、OutputStream及Writer

3.5.2 ServletResponseMethodArgumentResolver具体解析逻辑

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
       NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    if (mavContainer != null) {
       mavContainer.setRequestHandled(true);
    }

    Class<?> paramType = parameter.getParameterType();

    // 处理ServletResponse及HttpServletResponse
    if (ServletResponse.class.isAssignableFrom(paramType)) {
        // 获取响应实现类
       return resolveNativeResponse(webRequest, paramType);
    }

    // 获取ServletResponse,处理其他支持的类型
    return resolveArgument(paramType, resolveNativeResponse(webRequest, ServletResponse.class));
}

private <T> T resolveNativeResponse(NativeWebRequest webRequest, Class<T> requiredType) {
    T nativeResponse = webRequest.getNativeResponse(requiredType);
    if (nativeResponse == null) {
       throw new IllegalStateException(
             "Current response is not of type [" + requiredType.getName() + "]: " + webRequest);
    }
    return nativeResponse;
}

private Object resolveArgument(Class<?> paramType, ServletResponse response) throws IOException {
    // 从响应中获取OutputStream
    if (OutputStream.class.isAssignableFrom(paramType)) {
       return response.getOutputStream();
    }
    // 从响应中获取Writer
    else if (Writer.class.isAssignableFrom(paramType)) {
       return response.getWriter();
    }

    throw new UnsupportedOperationException("Unknown parameter type: " + paramType);
}
  • 14
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lm_ylj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值