Bootstrap

SpringMVC源码分析-HandlerAdapter(7)-ServletInvocableHandlerMethod组件分析

ServletInvocableHandlerMethod 继承结构

如图:

ServletInvocableHandlerMethod 也是一种 HandlerMethod,

相比 HandlerMethod 增加了参数解析,返回值处理等功能,最重要的是新增了方法的执行功能;

下面依次分析这三个组件;

1,HandlerMethod

HandlerMapping 组件中用到了 HandlerMethod;

HandlerMethod 用于封装 Handler 和处理请求的 Method;

HandlerMethod 的属性:

// Handler
private final Object bean;
// 传入的Handler为String类型时,需要使用beanFactory获取bean
private final BeanFactory beanFactory;
// bean类型
private final Class beanType;
// method
private final Method method;
// 当method是bridge method时设置为原有方法,否则设置为method
private final Method bridgedMethod;
// 处理请求的方法的参数
private final MethodParameter[] parameters;

private final HandlerMethod resolvedFromHandlerMethod;

需要注意的是:

  • HandlerMethod 所有属性都是 final 类型,创建后不可修改;

  • 如果 Handler 为 String 类型,需要从容器查找 bean;

  • 将 bean 属性变为容器中的 bean是使用 createWithResolvedBean 方法完成的;

  • 其实是使用容器中找到的 bean 和 HandlerMethod 原来的属性新建了一个 HandlerMethod;

createWithResolvedBean 源码:

public HandlerMethod createWithResolvedBean() {
  Object handler = this.bean;
  // handler为String类型,从容器获取Bean
  if (this.bean instanceof String) {
    String beanName = (String) this.bean;
    handler = this.beanFactory.getBean(beanName);
  }
  // 使用当前HandlerMethod和handler新建一个HandlerMethod
  return new HandlerMethod(this, handler);
}

private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
  Assert.notNull(handlerMethod, "HandlerMethod is required");
  Assert.notNull(handler, "Handler object is required");
  this.bean = handler;
  this.beanFactory = handlerMethod.beanFactory;
  this.beanType = handlerMethod.beanType;
  this.method = handlerMethod.method;
  this.bridgedMethod = handlerMethod.bridgedMethod;
  this.parameters = handlerMethod.parameters;
  this.resolvedFromHandlerMethod = handlerMethod;
}

parameters 的类型是 MethodParameter [],下面来看看这个类型;

MethodParameter

MethodParameter

// 参数所在方法
private final Method method;
// 参数的构成方法
private final Constructor constructor;
// 参数的需要,从0开始
private final int parameterIndex;
// 嵌套级别
private int nestingLevel = 1;
// 保存每层嵌套参数的序号
Map typeIndexesPerLevel;
// 容器类型,参数所属方法所在的类
private volatile Class containingClass;
// 参数类型
private volatile Class parameterType;
// Type型的参数类型
private volatile Type genericParameterType;
// 参数的注解
private volatile Annotation[] parameterAnnotations;
// 参数名称查找器
private volatile ParameterNameDiscoverer parameterNameDiscoverer;
// 参数名称
private volatile String parameterName;

private volatile MethodParameter nestedMethodParameter;

其中最重要的两个属性是:method和parameterIndex
因为有了这两个参数,参数类型,注释等都可以获取到

parameterNameDiscoverer参数名查找组件,可以查找出参数的名称

HandlerMothod定义了两个内部类来封装参数:
  HandlerMethodParameter封装方法调用的参数
  ReturnValueMethodParameter封装方法返回的参数
  ReturnValueMethodParameter继承自HandlerMethodParameter
  他们主要是用method和parameterIndex创建MethodParameter
  他们使用的method都是bridgedMethod,返回值使用的parameterIndex为-1

HandlerMethodParameter 源码:

protected class HandlerMethodParameter extends SynthesizingMethodParameter {

  public HandlerMethodParameter(int index) {
    super(HandlerMethod.this.bridgedMethod, index);
  }

  protected HandlerMethodParameter(HandlerMethodParameter original) {
    super(original);
  }

  @Override
  public Class getContainingClass() {
    return HandlerMethod.this.getBeanType();
  }

  @Override
  public  T getMethodAnnotation(Class annotationType) {
    return HandlerMethod.this.getMethodAnnotation(annotationType);
  }

  @Override
  public  boolean hasMethodAnnotation(Class annotationType) {
    return HandlerMethod.this.hasMethodAnnotation(annotationType);
  }

  @Override
  public HandlerMethodParameter clone() {
    return new HandlerMethodParameter(this);
  }
}

ReturnValueMethodParameter 源码:

private class ReturnValueMethodParameter extends HandlerMethodParameter {

  private final Object returnValue;

  public ReturnValueMethodParameter(Object returnValue) {
    super(-1);
    this.returnValue = returnValue;
  }

  protected ReturnValueMethodParameter(ReturnValueMethodParameter original) {
    super(original);
    this.returnValue = original.returnValue;
  }

  @Override
  public Class getParameterType() {
    return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
  }

  @Override
  public ReturnValueMethodParameter clone() {
    return new ReturnValueMethodParameter(this);
  }
}

2,InvocableHandlerMethod

InvocableHandlerMethod 继承自 HandlerMethod;

InvocableHandlerMethod 可以直接调用内部属性 method 对应的方法;

InvocableHandlerMethod 中增加了三个属性:

private WebDataBinderFactory dataBinderFactory;
private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

dataBinderFactory
  WebDataBinderFactory类型,可以创建WebDataBinder
  用于参数解析器ArgumentSolver中
  
argumentResolvers
  HandlerMethodArgumentResolverComposite类型
  用于解析参数
  
parameterNameDiscoverer
  ParameterNameDiscoverer类型
  用来获取参数名,用于MethodParameter中

InvocableHandlerMethod 中 Method的 调用方法是 invokeForRequest

invokeForRequest 源码:

public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
  
  // 获取方法参数
  Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
  if (logger.isTraceEnabled()) {
    logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
        "' with arguments " + Arrays.toString(args));
  }
  // 调用Method
  Object returnValue = doInvoke(args);
  if (logger.isTraceEnabled()) {
    logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
        "] returned [" + returnValue + "]");
  }
  return returnValue;
}

可以看到doInvoke方法是实际执行请求的方法
doInvoke是整个HandlerMethod系列处理器中最核心的方法

doInvoke 源码:

protected Object doInvoke(Object... args) throws Exception {
  // 强制方法可调用
  ReflectionUtils.makeAccessible(getBridgedMethod());
  try {
    // 执行
    return getBridgedMethod().invoke(getBean(), args);
  }
  catch (IllegalArgumentException ex) {
    assertTargetBean(getBridgedMethod(), getBean(), args);
    String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
    throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
  }
  catch (InvocationTargetException ex) {
    // Unwrap for HandlerExceptionResolvers ...
    Throwable targetException = ex.getTargetException();
    if (targetException instanceof RuntimeException) {
      throw (RuntimeException) targetException;
    }
    else if (targetException instanceof Error) {
      throw (Error) targetException;
    }
    else if (targetException instanceof Exception) {
      throw (Exception) targetException;
    }
    else {
      String text = getInvocationErrorMessage("Failed to invoke handler method", args);
      throw new IllegalStateException(text, targetException);
    }
  }
}

除去异常处理,最核心的一句是getBridgedMethod().invoke(getBean(), args);
真正执行的方法就是直接调用bridgedMethod的invoke方法

调用前使用ReflectionUtils.makeAccessible强制方法变为可调用方法
及时订单的处理器方法是private也可以在这里被调用

getMethodArgumentValues 源码:

private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {

  // 获取方法的参数
  MethodParameter[] parameters = getMethodParameters();
  // 保存解析的参数值
  Object[] args = new Object[parameters.length];
  for (int i = 0; i < parameters.length; i++) {
    MethodParameter parameter = parameters[i];
    // 给parameter设置参数名解析器parameterNameDiscoverer
    parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
    // 如果响应类型的参数已经在providedArgs中提供了,则直接设置到parameter
    args[i] = resolveProvidedArgument(parameter, providedArgs);
    if (args[i] != null) {
      continue;
    }
    // 使用argumentResolvers解析参数
    if (this.argumentResolvers.supportsParameter(parameter)) {
      try {
        args[i] = this.argumentResolvers.resolveArgument(
            parameter, mavContainer, request, this.dataBinderFactory);
        continue;
      }
      catch (Exception ex) {
        if (logger.isDebugEnabled()) {
          logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
        }
        throw ex;
      }
    }
    // 如果没解析出参数,抛出异常
    if (args[i] == null) {
      throw new IllegalStateException("Could not resolve method parameter at index " +
          parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
          ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
    }
  }
  return args;
}

1,调用父类getMethodParameters方法获取Method所有参数
2,定义一个Object类型的数组args用于保存解析出来的参数值
3,遍历每个参数进行解析,两种解析方法:
  1)在providedArgs中找
  2)使用argumentResolvers解析
  注:在RequestMappingHandlerAdapter中的调用并没有提供providedArgs
  所以只能用argumentResolvers来进行解析
4,为参数设置parameterNameDiscoverer用于获取参数名
  parameterNameDiscoverer可以在RequestMappingHandlerAdapter定义时配置
  默认使用DefaultParameterNameDiscoverer

InvocableHandlerMethod 就是在 HandlerMetod 基础上添加了方法的调用功能方法调用需要解析参数,所以也提供了解析参数的功能;

注解了 @InitBinder 和 @ModeAttribute 的方法就是封装成 InvocableHandlerMethod 对象,然后直接执行的;

3,ServletInvocableHandlerMethod

ServletInvocableHandlerMethod继承自InvocableHandlerMethod
在父类的基础上添加了三个功能:
1,对@ResponseStatus注解的支出
2,对返回值的处理
3,对异步处理结果的处理

@ResponseStatus 注解

@ResponseStatus注解用于处理器方法或返回值上
作用是对返回Response的Status进行设置
有两个参数:value(HttpStatus类型)和reason(String类型,默认为空串)错误原因

当一个方法注释了@ResponseStatus后,返回的Status会使用注释中的Status
如果处理器返回值为空或reason不为空,将中断处理直接返回(不再渲染页面)

返回值处理

对返回值的处理是使用returnValueHandlers属性完成的,
returnValueHandlers是HandlerMethodReturnValueHandler类型

异步处理暂时不做了解;

invokeAndHandle

ServletInvocableHandlerMethod处理请求使用的是invokeAndHandle方法
(注意,不是invokeAndHandler,没有r)

invokeAndHandle 源码:

public void invokeAndHandle(ServletWebRequest webRequest,
    ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {

  // 调用父类invokeForRequest执行请求
  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
  // 处理@ResponseStatus注解
  setResponseStatus(webRequest);
  // 处理返回值
  if (returnValue == null) {//判断返回值是不是null
    // Request的NotModified为真
    // 有@ResponseStatus
    // RequestHandled=true      
    // 三个条件有一个成立,则设置请求处理完成并返回
    if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
      mavContainer.setRequestHandled(true);
      return;
    }
  }
  // 返回值不为null,@ResponseStatus存在reason
  // 设置请求处理完成并返回
  else if (StringUtils.hasText(this.responseReason)) {
    mavContainer.setRequestHandled(true);
    return;
  }

  // 前边都不成立,则设置RequestHandled=false即请求未完成
  // 使用returnValueHandlers处理返回值
  mavContainer.setRequestHandled(false);
  try {
    this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
  }
  catch (Exception ex) {
    if (logger.isTraceEnabled()) {
      logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
    }
    throw ex;
  }
}

setResponseStatus:

private void setResponseStatus(ServletWebRequest webRequest) throws IOException {

  if (this.responseStatus == null) {
    return;
  }
  if (StringUtils.hasText(this.responseReason)) {
    webRequest.getResponse().sendError(this.responseStatus.value(), this.responseReason);
  }
  else {
    webRequest.getResponse().setStatus(this.responseStatus.value());
  }
  // 设置到request的属性,为了在redirect中使用
  webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, this.responseStatus);
}