写点什么

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

用户头像
Brave
关注
发布于: 刚刚

ServletInvocableHandlerMethod 继承结构


如图:

ServletInvocableHandlerMethod 也是一种 HandlerMethod,

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


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


1,HandlerMethod


HandlerMapping 组件中用到了 HandlerMethod;

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


HandlerMethod 的属性:

// Handlerprivate final Object bean;// 传入的Handler为String类型时,需要使用beanFactory获取beanprivate final BeanFactory beanFactory;// bean类型private final Class<?> beanType;// methodprivate final Method method;// 当method是bridge method时设置为原有方法,否则设置为methodprivate 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<Integer, Integer> 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 extends Annotation> T getMethodAnnotation(Class<T> annotationType) { return HandlerMethod.this.getMethodAnnotation(annotationType); }
@Override public <T extends Annotation> boolean hasMethodAnnotation(Class<T> 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);}
复制代码


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
SpringMVC源码分析-HandlerAdapter(7)-ServletInvocableHandlerMethod组件分析