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;
}
1. 先从 `providedArgs` 中获得参数。如果获得到,则进入下一个参数的解析。默认情况下,`providedArgs` 参数不会传递,所以可以暂时先忽略。保证核心逻辑的理解
2. 判断 `argumentResolvers` 是否支持当前的参数解析。如果支持,则进行解析。关于 HandlerMethodArgumentResolverComposite 的详细解析,见[ **《HandlerAdapter 组件(三)之 HandlerMethodArgumentResolver》** ][_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);
}
}
}
1. 设置方法为可访问
2. 通过反射执行该方法
注意,这里获取到的 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
返回值处理器是比较关键的两个组件,在接下来会逐个进行分析