首先我们直接看其结构图:
可以看到在这个类其是有继承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对方法的放回结果进行处理。