在初学SpringMVC框架时,我就一直有一个疑问,为什么controller方法上竟然可以放这么多的参数,而且都能得到想要的对象,比如HttpServletRequest
或HttpServletResponse
, 各种注解@RequestParam
、@RequestHeader
、@RequestBody
、@PathVariable
、@ModelAttribute
等。相信很多初学者都曾经感慨过。
这其实都是org.springframework.web.method.support.HandlerMethodArgumentResolver
的功劳。


package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
/**
* Strategy interface for resolving method parameters into argument values in
* the context of a given request.
*
* @author Arjen Poutsma
* @since 3.1
* @see HandlerMethodReturnValueHandler
*/
public interface HandlerMethodArgumentResolver {
/**
* Whether the given {@linkplain MethodParameter method parameter} is
* supported by this resolver.
* @param parameter the method parameter to check
* @return {@code true} if this resolver supports the supplied parameter;
* {@code false} otherwise
*/
boolean supportsParameter(MethodParameter parameter);
/**
* Resolves a method parameter into an argument value from a given request.
* A {@link ModelAndViewContainer} provides access to the model for the
* request. A {@link WebDataBinderFactory} provides a way to create
* a {@link WebDataBinder} instance when needed for data binding and
* type conversion purposes.
* @param parameter the method parameter to resolve. This parameter must
* have previously been passed to {@link #supportsParameter} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @param binderFactory a factory for creating {@link WebDataBinder} instances
* @return the resolved argument value, or {@code null}
* @throws Exception in case of errors with the preparation of argument values
*/
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
HandlerMethodArgumentResolver
接口包含两个接口方法
通过该方法我们如果需要对某个参数进行处理 只要此处返回true即可,
通过MethodParameter
可以获取该方法参数上的一些信息, 如方法参数中的注解信息等
public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class> paramType = parameter.getParameterType();
return (WebRequest.class.isAssignableFrom(paramType) ||
ServletRequest.class.isAssignableFrom(paramType) ||
MultipartRequest.class.isAssignableFrom(paramType) ||
HttpSession.class.isAssignableFrom(paramType) ||
Principal.class.isAssignableFrom(paramType) ||
Locale.class == paramType ||
TimeZone.class == paramType ||
"java.time.ZoneId".equals(paramType.getName()) ||
InputStream.class.isAssignableFrom(paramType) ||
Reader.class.isAssignableFrom(paramType) ||
HttpMethod.class == paramType);
}
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver
implements UriComponentsContributor {
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
@Override
public boolean supportsParameter(MethodParameter parameter) {
if (!parameter.hasParameterAnnotation(PathVariable.class)) {
return false;
}
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
return StringUtils.hasText(paramName);
}
return true;
}
resolveArgument
该方法就是对参数的解析,返回的Object会自动赋值到参数对象中。



SpringMVC自己的
HandlerMethodArgumentResolver
有哪些,并且会以什么样的顺序执行呢?
其实定义在RequestMappingHandlerAdapter
里:
/**
* Return the list of argument resolvers to use including built-in resolvers
* and custom resolvers provided via {@link #setCustomArgumentResolvers}.
*/
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
HandlerMethodArgumentResolver子类 |
注解 or 类 |
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver |
@RequestParam |
org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver |
@RequestParam |
org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver |
@PathVariable |
org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver |
@PathVariable |
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver |
@MatrixVariable |
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver |
@MatrixVariable |
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor |
@ModelAttribute |
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor |
@RequestBody |
org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver |
@RequestPart |
org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver |
@RequestHeader |
org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver |
@RequestHeader |
org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver |
@CookieValue |
org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver |
@Value |
org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver |
@SessionAttribute |
org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver |
@RequestAttribute |
org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver |
HttpServletRequest |
org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver |
HttpServletResponse |
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor |
HttpEntity |
org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver |
RedirectAttributes |
org.springframework.web.method.annotation.ModelMethodProcessor |
Model |
org.springframework.web.method.annotation.MapMethodProcessor |
Map |
org.springframework.web.method.annotation.ErrorsMethodArgumentResolver |
Errors |
org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver |
SessionStatus |
org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver |
UriComponentsBuilder |
而
RequestMappingHandlerAdapter
被注册进去是使用了
注解,可参考我的这篇文章《SpringMVC 解读——
》。

这里我们就不再自己重新写一个了,我们采用SpringMVC自带的一个
org.springframework.data.web.PageableHandlerMethodArgumentResolver
,
它将实现的功能如下:
绑定分页需要用到的参数,只是如何把这个Resolver注册进去呢,方式如下
class="org.springframework.data.web.PageableHandlerMethodArgumentResolver"/>