SpringMVC源码解读 --- 处理器适配器 - 2 源码解读前置知识ServletInvocableHandlerMethod类父子结构及源码分析

      首先我们直接看其结构图:

                                        

可以看到在这个类其是有继承HandlerMethod的,就是我们讲的用于描叙被@RequestMapping注解的方法。

    1、HandlerMethod类

    1、成员变量

public class HandlerMethod {

   protected final Log logger = LogFactory.getLog(getClass());
   private final Object bean;
   @Nullable
   private final BeanFactory beanFactory;
   private final Class<?> beanType;
   private final Method method;
   private final Method bridgedMethod;
   private final MethodParameter[] parameters;
   @Nullable
   private HttpStatus responseStatus;
   @Nullable
   private String responseStatusReason;
   @Nullable
   private HandlerMethod resolvedFromHandlerMethod;
        ............
}

  可以看到这个方法的全局变量,其是用来描叙Method,这个Method的参数描叙MethodParameter、以及桥方法、这个Method对应的Bean(这个Method所属的对象),这里将beanFactory也有设置。

    我们再通过一个demo来看下这个:

@RequestMapping(value = "methodHandler",method = RequestMethod.GET)
public String  methodHandler(@RequestParam("age") Integer age,
                               @RequestParam("name") String name,@RequestParam("type") Short type)
{
    System.out.println(".....methodHandler.....");
    return ".....methodHandler.....";
}

  然后看通过getHandler方法获取到的Handler:

  通过这张图片我们就可以清晰的这个这个HandlerMethod是描叙什么的,就不再过多赘叙了。

   2、方法

private void evaluateResponseStatus() {
   ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
   if (annotation == null) {
      annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
   }
   if (annotation != null) {
      this.responseStatus = annotation.code();
      this.responseStatusReason = annotation.reason();
   }
}

其主要是这个方法这个就是看当前的方法有没有@ResponseStatus注解,如果有,就将其设置到responseStatus(这个后面会有应用),然后在调用方法的时候再将这个status设置到response中,这个方法是私有方法,其的调用是在构造函数中:   

public HandlerMethod(Object bean, Method method) {
   Assert.notNull(bean, "Bean is required");
   Assert.notNull(method, "Method is required");
   this.bean = bean;
   this.beanFactory = null;
   this.beanType = ClassUtils.getUserClass(bean);
   this.method = method;
   this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
   this.parameters = initMethodParameters();
   evaluateResponseStatus();
}

      看了这个基础的HandlerMethod,我们再来看下InvokeHandlerMethod

2、InvokeHandlerMethod

   1、成员变量 

public class InvocableHandlerMethod extends HandlerMethod {

   @Nullable
   private WebDataBinderFactory dataBinderFactory;

   private HandlerMethodArgumentResolverComposite argumentResolvers = new HandlerMethodArgumentResolverComposite();

   private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
  ..............
}

  1、WebDataBinderFactory

  这个WebDataBinderFactory 就是去创建WebDataBinder

public interface WebDataBinderFactory {
   WebDataBinder createBinder(NativeWebRequest webRequest, @Nullable Object target, String objectName)
         throws Exception;
}

然后这个WebDataBinder主要是与@InitBinder注解相关的,然后这个WebDataBinder其是与字段类型转换,以及进行相关属性设置有关,关于WebDataBinder与WebDataBinderFactory 的类结构后面再梳理。

  2、HandlerMethodArgumentResolverComposite

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

   protected final Log logger = LogFactory.getLog(getClass());

   private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();

   private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
         new ConcurrentHashMap<>(256);
    ...............
}

       可以看到这个类继承HandlerMethodArgumentResolver接口,同时是放HandlerMethodArgumentResolver的(argumentResolvers ),这个HandlerMethodArgumentResolver接口可以看上一篇的梳理

  2、方法

  1、invokeForRequest

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {

   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
   Object returnValue = doInvoke(args);
   return returnValue;
}

  所以对于request请求对应@RequestMapping注解的方法(HandlerMethod、Handler)的执行就是在这里,(providedArgs是干嘛的?后面再解答)。

2、getMethodArgumentValues

private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable 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.initParameterNameDiscovery(this.parameterNameDiscoverer);
      args[i] = resolveProvidedArgument(parameter, providedArgs);
      if (args[i] != null) {
         continue;
      }
      if (this.argumentResolvers.supportsParameter(parameter)) {
         try {
            args[i] = this.argumentResolvers.resolveArgument(
                  parameter, mavContainer, request, this.dataBinderFactory);
            continue;
         }
          ..........
      if (args[i] == null) {
         throw new IllegalStateException("Could not resolve method parameter at index " +
           parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
         ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
       }
   }
   return args;
}
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
   this.parameterNameDiscoverer = parameterNameDiscoverer;
}

    这个方法就是对请求方法的参数进行解析及获取,实现是获取这个方法需要哪些参数MethodParameter,再遍历获取。

3、resolveProvidedArgument

@Nullable
private Object resolveProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) {
   if (providedArgs == null) {
      return null;
   }
   for (Object providedArg : providedArgs) {
      if (parameter.getParameterType().isInstance(providedArg)) {
         return providedArg;
      }
   }
   return null;
}

  这里就解释了providedArgs是干什么用的,如果方法的参数类型与providedArgs的类型时一样的,就直接返回对应providedArgs的值,不再需要进行测试解析了(这里目前找到的再SpringMVC中的使用主要是对WebDataBinder的使用(@InitBinder))。

args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
   continue;
}

4、argumentResolvers.supportsParameter(HandlerMethodArgumentResolverComposite)

   这里是调用的HandlerMethodArgumentResolverComposite的接口:

@Override
public boolean supportsParameter(MethodParameter parameter) {
   return (getArgumentResolver(parameter) != null);
}
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
   HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
   if (result == null) {
      for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
         if (methodArgumentResolver.supportsParameter(parameter)) {
            result = methodArgumentResolver;
            this.argumentResolverCache.put(parameter, result);
            break;
         }
      }
   }
   return result;
}

所以这里就是,就是通过supportsParameter判断有没有处理该方法参数对应的HandlerMethodArgumentResolver。

能找到再调用resolveArgument方法去进行对应参数的解析,不能获取就报错IllegalStateException。

5、argumentResolvers.resolveArgument(HandlerMethodArgumentResolverComposite )

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

   HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
   if (resolver == null) {
      throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
   }
   return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}

  上面2-5的方法都是由getMethodArgumentValues方法的调用衍生出来的,先在这个方法就调用完成,已经获取到要执行对应方法的入参了,现在再回到前面

6、doInvoke(args)

   这个方法就是对对应方法的执行了:

protected Object doInvoke(Object... args) throws Exception {
   ReflectionUtils.makeAccessible(getBridgedMethod());
   try {
      return getBridgedMethod().invoke(getBean(), args);
   }
   catch (IllegalArgumentException ex) {
      .........
      throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
   }
   catch (InvocationTargetException ex) {
        .........
   }
}

3、ServletInvocableHandlerMethod

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
   .......
   @Nullable
   private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
       .........
}

  1、成员变量

   这个我们可以看到主要是HandlerMethodReturnValueHandlerComposite

  然后这个HandlerMethodReturnValueHandlerComposite与前面HandlerMethodArgumentResolverComposite是类似的,只是HandlerMethodArgumentResolver是放HandlerMethodArgumentResolver的,HandlerMethodReturnValueHandlerComposite是放HandlerMethodReturnValueHandler的。

   2、方法

      1、invokeAndHandle

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

   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);

   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         mavContainer.setRequestHandled(true);
         return;
      }
   }
   else if (StringUtils.hasText(getResponseStatusReason())) {
      mavContainer.setRequestHandled(true);
      return;
   }

   mavContainer.setRequestHandled(false);
   try {
      this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
   }
   ...........
}

可以看到这里首先就是调用invokeForRequest(InvokeHandlerMethod)方法获取执行对应方法的调用结果。然后setResponseStatus方法的调用,再通过isRequestNotModified方法(如果对应请求的内容没有进行修改)、getResponseStatus(如果有设置response的status)、isRequestHandled(请求已经处理了),就设置mavContainer.setRequestHandled(true)再return。如果没有return,然后再通过returnValueHandlers.handleReturnValue去处理返回结果。

  2、setResponseStatus

private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
   HttpStatus status = getResponseStatus();
   if (status == null) {
      return;
   }
   HttpServletResponse response = webRequest.getResponse();
   if (response != null) {
      String reason = getResponseStatusReason();
      if (StringUtils.hasText(reason)) {
         response.sendError(status.value(), reason);
      }
      else {
         response.setStatus(status.value());
      }
   }

   // To be picked up by RedirectView
   webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}

  可以看到这个方法就是看有没有设置status(前面在HandlerMethod有梳理这个值的设置通过@ResponseStatus注解),如果没有设置就直接return,如果有设置,就将对应HttpStatus设置到response中。

    最后我们总结下ServletInvocableHandlerMethod方法,这个类就是将被@RequestMapping注解的方法描叙就来,再通过方法去进行这个方法执行的准备(通过HandlerMethodArgumentResolver去进行方法对应参数的获取及类型转化),获取到对应参数后,再通过invoke方法进行执行,执行后,再通过HandlerMethodResultResolver对方法的放回结果进行处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值