Spring MVC 源码分析 - HandlerAdapter 组件(二)之 ServletInvocableHandlerMethod
参考 知识星球 中 芋道源码 星球的源码解析,一个活跃度非常高的 Java 技术社群,感兴趣的小伙伴可以加入 芋道源码 星球,一起学习😄
该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读
Spring 版本:5.1.14.RELEASE
该系列其他文档请查看:《精尽 Spring MVC 源码分析 - 文章导读》
HandlerAdapter 组件
HandlerAdapter 组件,处理器的适配器。因为处理器 handler
的类型是 Object 类型,需要有一个调用者来实现 handler
是怎么被执行。Spring 中的处理器的实现多变,比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口,也可以用 @RequestMapping
注解将方法作为一个处理器等,这就导致 Spring MVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器
由于 HandlerMapping 组件涉及到的内容较多,考虑到内容的排版,所以将这部分内容拆分成了五个模块,依次进行分析:
- 《HandlerAdapter 组件(一)之 HandlerAdapter》
- 《HandlerAdapter 组件(二)之 ServletInvocableHandlerMethod》
- 《HandlerAdapter 组件(三)之 HandlerMethodArgumentResolver》
- 《HandlerAdapter 组件(四)之 HandlerMethodReturnValueHandler》
- 《HandlerAdapter 组件(五)之 HttpMessageConverter》
HandlerAdapter 组件(二)之 ServletInvocableHandlerMethod
本文是接着《HandlerAdapter 组件(一)之 HandlerAdapter》一文来分享 ServletInvocableHandlerMethod 组件。在 HandlerAdapter
执行处理器的过程中,主要的任务还是交由它来完成的。ServletInvocableHandlerMethod 封装 HandlerMethod
处理器对象,它还包含 HandlerMethodArgumentResolver
参数解析器和 HandlerMethodReturnValueHandler
返回值处理器等组件。虽然内容不多,但还是有必要另一篇进行分析。
回顾
先来回顾一下 RequestMappingHandlerAdapter
是如何创建 ServletInvocableHandlerMethod 对象的,可以回到 《HandlerAdapter 组件(一)之 HandlerAdapter》 中 RequestMappingHandlerAdapter 小节下面的 invokeHandlerMethod
方法,如下:
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
HandlerMethod handlerMethod) throws Exception {
// ... 省略相关代码
// <4> 创建 ServletInvocableHandlerMethod 对象,并设置其相关属性
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// ... 省略相关代码
// <9> 执行调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// ... 省略相关代码
}
protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
return new ServletInvocableHandlerMethod(handlerMethod);
}
-
将
HandlerMethod
处理器封装成 ServletInvocableHandlerMethod 对象,然后设置参数解析器和返回值处理器 -
这里设置了 ServletInvocableHandlerMethod 对象的
resolvers
、parameterNameDiscoverer
和returnValueHandlers
相关属性 -
调用
invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,执行处理器
类图
ServletInvocableHandlerMethod 的整体类图如下:
依次分析
HandlerMethod
org.springframework.web.method.HandlerMethod
,处理器的方法的封装对象
在《HandlerMapping 组件(三)之 AbstractHandlerMethodMapping》的 AbstractHandlerMethodMapping 小节中已经分析过该对象
InvocableHandlerMethod
org.springframework.web.method.support.InvocableHandlerMethod
,继承 HandlerMethod 类,可 invoke 调用的 HandlerMethod 实现类。
😈 也就是说,HandlerMethod 只提供了处理器的方法的基本信息,不提供调用逻辑。
构造方法
public class InvocableHandlerMethod extends HandlerMethod {
/** 无参时的入参,空数组 */
private static final Object[] EMPTY_ARGS = new Object[0];
/** 数据绑定器工厂 */
@Nullable
private WebDataBinderFactory dataBinderFactory;
/** 参数解析器组合对象 */
private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
/** 方法的参数名称发现器 */
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
}
invokeForRequest
invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,执行请求,方法如下:
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// <1> 解析参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// <2> 执行调用
return doInvoke(args);
}
-
调用
getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,解析方法的参数们,如下:protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获得方法的参数 MethodParameter[] parameters = getMethodParameters(); // 无参,返回空数组 if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } // 将参数解析成对应的类型 Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { // 获得当前遍历的 MethodParameter 对象,并设置 parameterNameDiscoverer 到其中 MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); // <1> 先从 providedArgs 中获得参数。如果获得到,则进入下一个参数的解析,默认情况 providedArgs 不会传参 args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } // <2> 判断 resolvers 是否支持当前的参数解析 if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { // 执行解析,解析成功后,则进入下一个参数的解析 args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
- 先从
providedArgs
中获得参数。如果获得到,则进入下一个参数的解析。默认情况下,providedArgs
参数不会传递,所以可以暂时先忽略。保证核心逻辑的理解 - 判断
argumentResolvers
是否支持当前的参数解析。如果支持,则进行解析。关于 HandlerMethodArgumentResolverComposite 的详细解析,见《HandlerAdapter 组件(三)之 HandlerMethodArgumentResolver》
- 先从
-
调用
doInvoke(Object... args)
方法,执行方法的调用,方法如下:@Nullable protected Object doInvoke(Object... args) throws Exception { // <1> 设置方法为可访问 ReflectionUtils.makeAccessible(getBridgedMethod()); try { // <2> 执行调用 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(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 { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }
- 设置方法为可访问
- 通过反射执行该方法
注意,这里获取到的 Method 对象可能是桥接方法,桥接方法:如果泛型对象,编译器则会自动生成一个桥接方法(java1.5向后兼容)
ServletInvocableHandlerMethod
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod
,继承 InvocableHandlerMethod 类,用于 DispatcherServlet 执行 HandlerMethod 处理器
构造方法
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");
/** 返回结果处理器组合对象 */
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
public ServletInvocableHandlerMethod(Object handler, Method method) {
super(handler, method);
}
public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
super(handlerMethod);
}
}
invokeAndHandle
invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,处理请求,执行处理器,并处理返回结果,方法如下:
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// <1> 执行调用
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// <2> 设置响应状态码
setResponseStatus(webRequest);
// <3> 设置 ModelAndViewContainer 为请求已处理,返回,和 @ResponseStatus 注解相关
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// <4> 设置 ModelAndViewContainer 为请求未处理
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// <5> 处理返回值
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
-
调用 InvocableHandlerMethod 父类的
invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs)
方法,执行调用 -
调用
setResponseStatus(ServletWebRequest webRequest)
设置响应的状态码,方法如下:private void setResponseStatus(ServletWebRequest webRequest) throws IOException { // 获得状态码,和 @ResponseStatus 注解相关 HttpStatus status = getResponseStatus(); if (status == null) { return; } // 设置响应的状态码 HttpServletResponse response = webRequest.getResponse(); if (response != null) { String reason = getResponseStatusReason(); if (StringUtils.hasText(reason)) { // 有 reason ,则设置 status + reason response.sendError(status.value(), reason); } else { // 无 reason ,则仅设置 status response.setStatus(status.value()); } } // To be picked up by RedirectView // 为了 RedirectView ,所以进行设置 webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status); }
-
设置 ModelAndViewContainer 为请求已处理,返回,和 @ResponseStatus 注解相关
-
设置 ModelAndViewContainer 为请求未处理
-
调用
HandlerMethodReturnValueHandlerComposite
的handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
方法,处理返回值。详细解析,见《HandlerAdapter 组件(四)之 HandlerMethodReturnValueHandler》
总结
在 HandlerAdapter
执行 HandlerMethod
处理器的过程中,会将该处理器封装成 ServletInvocableHandlerMethod 对象,通过该对象来执行处理器。因为 HandlerMethod
处理器里面仅包含了方法的所有信息,如何解析参数、调用对应的方法、以及处理返回结果,它本身并不知道如何去处理,这里 Spring MVC 借助于 ServletInvocableHandlerMethod 对象来进行操作,原理就是通过反射机制执行该方法
其中涉及到的 HandlerMethodArgumentResolver
参数解析器和 HandlerMethodReturnValueHandler
返回值处理器是比较关键的两个组件,在接下来会逐个进行分析
参考文章:芋道源码《精尽 Spring MVC 源码分析》