一、HandlerMethodArgumentResolver源码分析
1.在DispatcherServlet中,HandlerAdapter调用handle返回ModleAndView
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
2.在RequestMappingHandlerAdapter中,handleInternal方法中的invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
...省略
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
invokeAndHandle方法用于处理参数请求,并返回参数对象值
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
需要实现support是否支持,以及resolveArgument返回参数值
二、实践
1.定义annotation
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenAccount {
}
2.自定义HandlerMethodArgumentResolver
@Component
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(Account.class)
&& parameter.hasParameterAnnotation(TokenAccount.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String mobile = webRequest.getHeader(HttpHeaderConst.MOBILE);
return new Account(mobile);
}
}
3.参数使用
@RequestMapping(value = "/test/getAccount", method = RequestMethod.GET)
public void test(@TokenAccount Account account) {
}