我们在控制器中添加一个方法用于测试:
// http://localhost:8888/user/33/name/zhangsan?age=12&inters=reading,playing,listening
@GetMapping("/user/{id}/name/{username}")
public Map<String, Object> getUser(@PathVariable("id") Integer id,
@PathVariable("username") String username,
@PathVariable Map<String, String> pv,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String, String> headers,
@RequestParam("age") Integer age,
@RequestParam("inters") List<String> inters,
@CookieValue("cookie") String cookie) {
Map<String, Object> map = new HashMap<>();
map.put("id", id);
map.put("username", username);
map.put("pv", pv);
map.put("userAgent", userAgent);
map.put("headers", headers);
map.put("age", age);
map.put("inters", inters);
map.put("cookie", cookie);
return map;
}
浏览器访问,各参数的值都已经获得了:
所有的请求处理都是在DispatcherServlet,并且在doDispatcher()方法中,对于请求参数的处理核心代码就是:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
进入到handle发现是一个接口:
public interface HandlerAdapter {
boolean supports(Object var1);
@Nullable
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
我们需要查看具体的实现类AbstractHandlerMethodAdapter类,这是一个抽象类,因为我们使用了@RequestMapping,匹配的适配器就是这个。该类中有一个handle()方法,该方法内又调用了抽象方法handleInternal,执行后会返回一个ModelAndView。
查看handleInternal()方法的实现方法在RequestMappingHandlerAdapter类中,该方法的代码如下:
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
this.checkRequest(request);
ModelAndView mav;
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
这个方法中最核心的代码是mav = this.invokeHandlerMethod(request, response, handlerMethod);,查看invokeHandlerMethod()方法的源码:
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
Object result;
try {
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = this.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);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (!asyncManager.isConcurrentHandlingStarted()) {
ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
return var15;
}
result = null;
} finally {
webRequest.requestCompleted();
}
return (ModelAndView)result;
}
这个方法内有两个变量需要注意,也是核心:
argumentResolvers参数解析器,有26种,底层是一个HandlerMethodArgumentResolver接口
public interface HandlerMethodArgumentResolver {
// 解析器是否支持当前参数
boolean supportsParameter(MethodParameter var1);
// 将request种的请求参数解析到控制器类Controller的参数上
@Nullable
Object resolveArgument(MethodParameter var1, @Nullable ModelAndViewContainer var2, NativeWebRequest var3, @Nullable WebDataBinderFactory var4) throws Exception;
}
我们来查看参数解析器,如果我们使用了@PathVariable注解获得参数就会通过下面的PathVariableMethodArgumentResolver方法参数解析器,其他类型的参数也会如此:
returnValueHandlers是返回值处理器,决定了目标方法到底能够写多少种类型的返回值,默认有15种
看完参数解析器和返回值处理器后,下面就开始是invokeAndHandle()方法,打断点跟踪该方法:
该方法在ServletInvocableHandlerMethod类种,源码如下,重要的是里面的invokeForRequest()方法
跟踪invokeForRequest()方法,来到InvocableHandlerMethod类,查看方法源码如下:
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = this.getMethodArgumentValues(request, mavContainer, providedArgs);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Arguments: " + Arrays.toString(args));
}
return this.doInvoke(args);
}
// 核心方法,获取参数值
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 获取到方法的所有参数声明,如注解、类型等
MethodParameter[] parameters = this.getMethodParameters();
// 判断参数是否为空,如果为空则直接返回,无须确定任何值
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
} else {
Object[] args = new Object[parameters.length];
// 挨个遍历参数值
for(int i = 0; i < parameters.length; ++i) {
MethodParameter parameter = parameters[i];
// 确定参数的名字
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] == null) {
// 先判断当前解析器是否支持这种类型,不支持则进行遍历,则直到查找到支持的解析器
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 var10) {
if (this.logger.isDebugEnabled()) {
String exMsg = var10.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
this.logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw var10;
}
}
}
return args;
}
}
获取到的参数声明:
拿到参数解析器后,我们就可以获取到参数的值了
我们进入resolveArgument()方法中
进入到HandlerMethodArgumentResolver接口中,关注实现该接口的实现类AbstractNamedValueMethodArgumentResolver,该类又是一个抽象类,有resolveArgument()方法能够解析参数的值。
AbstractNamedValueMethodArgumentResolver抽象类又有很多具体实现类,解析各种参数