Spring 知识面面通 之 HandlerMethodArgumentResolver方法参数解析器
HandlerMethodArgumentResolver
是一个策略接口,用于在给定请求上下文中解析方法参数。平时开发中使用的频次比较高,@CookieValue
、@RequestBody
、@PathVariable
、@RequestParam
等等这些注解都是基于这个策略接口来完成参数解析的。
HandlerMethodArgumentResolver
API定义
package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
/**
* 在给定请求的上下文中将方法参数解析为参数值的策略接口.
*/
public interface HandlerMethodArgumentResolver {
/**
* 此解析程序是否支持给定的MethodParameter.
* @param parameter 检查参数的方法.
* @return 如果此解析器支持提供的参数返回true,否则返回false.
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 从给定请求将方法参数解析为参数值.
* ModelAndViewContainer提供对请求模型的访问.
* WebDataBinderFactory提供了一种在需要数据绑定和类型转换时创建WebDataBinder实例的方法.
* @param parameter 要解析的方法参数,此参数之前必须传递给supportsParameter,后者必须返回true.
* @param mavContainer 当前请求的ModelAndViewContainer.
* @param webRequest 当前请求.
* @param binderFactory 用于创建WebDataBinder实例的工厂.
* @return 已解析的参数值,如果不可解析,则为null.
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
HandlerMethodArgumentResolver
调用逻辑
1) DispatcherServlet
是Spring MVC的请求入口,DispatcherServlet
类包含了静态代码块,用于加载类路径下DispatcherServlet.properties
中包含的默认策略。
/**
* 从属性文件加载默认策略实现.
* 这是目前严格的内部,不打算由应用程序开发人员定制.
*/
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
2) DispatcherServlet.properties
中包含org.springframework.web.servlet.HandlerAdapter
的配置。
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
① org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
HttpRequestHandlerAdapter
是Http请求处理适配器,仅仅支持对HTTP请求处理器的适配,最终通过HttpRequestHandler.handleRequest(...)
请求处理。
② org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter
是简单控制器处理器适配器,将HTTP请求适配到一个控制器的实现进行处理。SimpleControllerHandlerAdapter
将会调用处理器的handleRequest(...)
方法进行功能处理,该处理方法返回一个ModelAndView
给DispatcherServlet
。
③ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
RequestMappingHandlerAdapter
继承了AbstractHandlerMethodAdapter
类,真正意义上实现了HandlerAdapter
接口定义的功能。
RequestMappingHandlerAdapter
采用反射机制调用URL
请求对应的Controller
控制器中的方法,并对方法参数进行解析处理,返回执行结果,完成HandlerAdapter
的工作。
3) DispatcherServlet
的initStrategies(...)
负责初始化默认策略。
/**
* 初始化这个Servlet使用的策略对象.
* 可以在子类中重写,以便初始化进一步的策略对象.
*/
protected void initStrategies(ApplicationContext context) {
// 初始化此类使用的MultipartResolver.
initMultipartResolver(context);
// 初始化此类使用的LocaleResolver.
initLocaleResolver(context);
// 初始化此类使用的ThemeResolver.
initThemeResolver(context);
// 初始化此类使用的HandlerMappings.
initHandlerMappings(context);
// 初始化此类使用的HandlerAdapters.
initHandlerAdapters(context);
// 初始化此类使用的HandlerExceptionResolvers.
initHandlerExceptionResolvers(context);
// 初始化此类使用的RequestToViewNameTranslator.
initRequestToViewNameTranslator(context);
// 初始化此类使用的ViewResolvers.
initViewResolvers(context);
// 初始化此类使用的FlashMapManager.
initFlashMapManager(context);
}
4) DispatcherServlet
的doService(...)
和doDispatch(...)
用于进行请求处理,着重来看下doDispatch(...)
方法:
① doDispatch(...)
负责实际请求的分发,将请求分发给处理器。
② doDispatch(...)
负责处理所有的HTTP方法,可以参照FrameworkServlet
的doXXX(...)
系列方法和DispatcherServlet
的doService(...)
方法。
③ 处理程序将按照顺序处理Servlet
的HandlerMappings
。
④ HandlerAdapter
通过查询DispatcherServlet
的handlerAdapters
来获取handlerAdapter
。
⑤ 实际调用时,由于具体的HandlerAdapter
或处理器程序来确定具体的实例。
⑥ doDispatch(...)
方法中mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
负责调用处理器处理请求的方法。
/**
* 实际分发请求给处理程序.
* 处理程序将按照顺序处理Servlet的HandlerMappings.
* HandlerAdapter将通过查询Servlet已配置的HandlerAdapter来获取,以找到第一个支持handler类的HandlerAdapter.
* 所有的HTTP方法都由这个方法处理.
* 由HandlerAdapter或处理程序自己决定哪些方法是可接受的.
* @param request 当前请求实例.
* @param response 当前响应实例.
* @throws Exception .
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
// 处理器执行链.
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 确认是否multipart/form-data请求.
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获得当前请求的处理器.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取当前请求的处理器适配器.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理last-modified请求头.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 调用处理器的applyPreHandle方法.
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际调用处理器方法处理请求.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 处理默认视图.
applyDefaultViewName(processedRequest, mv);
// 调用处理器的applyPostHandle方法.
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// 从4.3开始,同时会处理从handler方法抛出的错误,使它们可以用于@ExceptionHandler方法和其他场景.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理转发结果.
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 调用处理器的triggerAfterCompletion方法.
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 调用处理器的triggerAfterCompletion方法.
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 代替postHandle和afterCompletion.
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 清除multipart/form-data请求使用的所有资源.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
5) 通过 2)
中对处理器也进行了简介,主要来看下org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
,它负责请求方法参数的绑定处理。
RequestMappingHandlerAdapter
继承了AbstractHandlerMethodAdapter
,AbstractHandlerMethodAdapter
进行了上层抽象,RequestMappingHandlerAdapter
的handleInternal(...)
方法负责进行请求处理。
调用流程:
DispatcherServlet.doDispatch(...) --调用-->
AbstractHandlerMethodAdapter.supports(..) --调用-->
RequestMappingHandlerAdapter.supportsInternal(...) --调用-->
AbstractHandlerMethodAdapter.handle(...) --调用-->
RequestMappingHandlerAdapter.handleInternal(...) --调用-->
RequestMappingHandlerAdapter.invokeHandlerMethod(...) --调用-->
ServletInvocableHandlerMethod.invokeAndHandle(...) --调用-->
InvocableHandlerMethod.invokeForRequest(...) --调用-->
InvocableHandlerMethod.getMethodArgumentValues(...) --调用-->
HandlerMethodArgumentResolverComposite.supportsParameter(...) --调用-->
HandlerMethodArgumentResolverComposite.resolveArgument(...) --调用-->
HandlerMethodArgumentResolverComposite.getArgumentResolver(...) --调用-->
遍历HandlerMethodArgumentResolverComposite.argumentResolvers --调用-->
HandlerMethodArgumentResolverComposite.getArgumentResolver查找到第一个支持方法参数的解析器 --调用-->
调用特定解析器解析方法参数
调用流程中仅简单描述了请求的处理过程,具体细节得个人自行去了解。
6) HandlerMethodArgumentResolverComposite
HandlerMethodArgumentResolverComposite
混合实现,用于承载多个HandlerMethodArgumentResolver
,主要对HandlerMethodArgumentResolver
进行了封装,这种模式在Spring设计中应用比较多,主要是因为对于不同场景实现不尽相同。
查看HandlerMethodArgumentResolverComposite.getArgumentResolver(...)
来进行实际HandlerMethodArgumentResolver
的查找。
/**
* 查找支持给MethodParameter的解析程序.
*/
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
// 从缓存中获取HandlerMethodArgumentResolver.
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
// 遍历argumentResolvers,找到适合当前MethodParameter的HandlerMethodArgumentResolver.
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
// 调用具体的解析程序处理.
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
7) 从 6)
继续向下调用,会调用具体的HandlerMethodArgumentResolver
实现类完成方法参数绑定。
HandlerMethodArgumentResolver
默认实现
Spring提供的HandlerMethodArgumentResolver
实现有很多,都是针对某些特定应用场景的参数解析。
类结构图中,可以看出Spring中,方法参数注解与图中类名及其相似,可以一一对应上,用来处理格式各样的方法参数。
若文中存在错误和不足,欢迎指正!