在上一篇文章中我们分析了SpringMVC对简单对象和@RequestParam注解的解析过程,这一章中我们继续分析其他形式的参数解析过程。
ServletRequestMethodArgumentResolver
下面来看一下我们的第一个请求:http://localhost:8086/allRequestFormat/requestAndResponseRequest?userName=zhangsan
对应的后台处理代码是:
@RequestMapping("requestAndResponseRequest") public String requestAndResponseRequest(HttpServletRequest request, HttpServletResponse response) { System.out.println("userName" + request.getParameter("userName")); return "这是一个接收Request和Response的请求"; }我们的请求处理方法中的两个参数是HttpServletRequest和HttpServletResponse类型,那么SpringMVC在调用requestAndResponseRequest这个方法的时候是怎么解析到这两个参数的值的呢?我们先看HttpServletRequest这个参数,这个参数是ServletRequestMethodArgumentResolver这个类来解析的。在上一篇文章中,我们知道通过调用argumentResolvers. supportsParameter这个方法来判断HandlerMethodArgumentResolver的实现类是否支持对应的参数的解析,和 resolveArgument方法来实现真正的参数解析。
所以我们先看一下ServletRequestMethodArgumentResolver这个类中的supportsParameter这个方法的内容:
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) || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || HttpMethod.class == paramType || Locale.class == paramType || TimeZone.class == paramType || "java.time.ZoneId".equals(paramType.getName())); }从上面的代码中我们可以看到如果 参数类型为WebRequest类型、ServletRequest类型、MultipartRequest类型、HttpSession类型、Principal类型、InputStream类型、Reader类型或者HttpMethod类型、Locale类型、TimeZone类型、ZoneId类型则使用这个参数解析器进行参数的解析工作。
下面我们在看一下ServletRequestMethodArgumentResolver是怎么进行参数解析工作的:
@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Class<?> paramType = parameter.getParameterType(); //如果是WebRequest的子类 if (WebRequest.class.isAssignableFrom(paramType)) { //不是NativeWebRequest的实现类,则抛出异常 if (!paramType.isInstance(webRequest)) { throw new IllegalStateException( "Current request is not of type [" + paramType.getName() + "]: " + webRequest); } //直接返回传进来的NativeWebRequest return webRequest; } //从传进来的webRequest中获取HttpServletRequest对象 HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); //如果是ServletRequest的类型或者为MultipartRequest的类型 if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) { //判断类型是否一致 Object nativeRequest = webRequest.getNativeRequest(paramType); if (nativeRequest == null) { throw new IllegalStateException( "Current request is not of type [" + paramType.getName() + "]: " + request); } return nativeRequest; } else if (HttpSession.class.isAssignableFrom(paramType)) { //从request中得到HttpSession对象 HttpSession session = request.getSession(); if (session != null && !paramType.isInstance(session)) { throw new IllegalStateException( "Current session is not of type [" + paramType.getName() + "]: " + session); } return session; } else if (InputStream.class.isAssignableFrom(paramType)) { //从request中得到InputStream对象 InputStream inputStream = request.getInputStream(); if (inputStream != null && !paramType.isInstance(inputStream)) { throw new IllegalStateException( "Request input stream is not of type [" + paramType.getName() + "]: " + inputStream); } return inputStream; } else if (Reader.class.isAssignableFrom(paramType)) { //从request中得到Reader对象 Reader reader = request.getReader(); if (reader != null && !paramType.isInstance(reader)) { throw new IllegalStateException( "Request body reader is not of type [" + paramType.getName() + "]: " + reader); } return reader; } else if (Principal.class.isAssignableFrom(paramType)) { //从request中得到Reader对象 Principal userPrincipal = request.getUserPrincipal(); if (userPrincipal != null && !paramType.isInstance(userPrincipal)) { throw new IllegalStateException( "Current user principal is not of type [" + paramType.getName() + "]: " + userPrincipal); } return userPrincipal; } else if (HttpMethod.class == paramType) { //从request中得到请求类型的值 return HttpMethod.resolve(request.getMethod()); } else if (Locale.class == paramType) { //从Request上下文中获取国际化对象 return RequestContextUtils.getLocale(request); } else if (TimeZone.class == paramType) { //从Request上下文中获取时区对象 TimeZone timeZone = RequestContextUtils.getTimeZone(request); return (timeZone != null ? timeZone : TimeZone.getDefault()); } else if ("java.time.ZoneId".equals(paramType.getName())) { //JDK1.8时区 return ZoneIdResolver.resolveZoneId(request); } else { // Should never happen... throw new UnsupportedOperationException( "Unknown parameter type [" + paramType.getName() + "] in " + parameter.getMethod()); } }从上面的代码中我们发现最主要的是NativeWebRequest这个对象,我们可以从这个对象中获取到HttpServletRequest,从HttpServletRequest中获取一系列的其他对象的值。我们可以看一下NativeWebRequest这个对象的值是怎么创建的。在RequestMappingHandlerAdapter#invokeHandlerMethod中有这样一段代码:
ServletWebRequest webRequest = new ServletWebRequest(request, response);在ServletWebRequest这个对象中持有request和response这两个对象的引用。ServletWebRequest的UML类图关系如下:
所以resolveArgument中的NativeWebRequest其实是ServletWebRequest这个对象。
ServletResponseMethodArgumentResolver
上面分析完了HttpServletRequest,我们还有一个参数类型是HttpServletResponse,那么这个HttpServletResponse这个参数是谁解析的呢?是ServletResponseMethodArgumentResolver来解析的。我们看一下它的supportsParameter方法的实现:
@Override public boolean supportsParameter(MethodParameter parameter) { Class<?> paramType = parameter.getParameterType(); return (ServletResponse.class.isAssignableFrom(paramType) || OutputStream.class.isAssignableFrom(paramType) || Writer.class.isAssignableFrom(paramType)); }ServletResponseMethodArgumentResolver解析的参数类型是: ServletResponse类型、OutputStream类型和Writer类型。我们再看下一resolveArgument方法中对参数解析的实现:
@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { if (mavContainer != null) { mavContainer.setRequestHandled(true); } //从webRequest获取HttpServletResponse对象,我们前面说了webRequest持有HttpServletResponse对象的引用 HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); Class<?> paramType = parameter.getParameterType(); //ServletResponse类型 if (ServletResponse.class.isAssignableFrom(paramType)) { Object nativeResponse = webRequest.getNativeResponse(paramType); if (nativeResponse == null) { throw new IllegalStateException( "Current response is not of type [" + paramType.getName() + "]: " + response); } return nativeResponse; }//从HttpServletResponse中获取OutputStream对象 else if (OutputStream.class.isAssignableFrom(paramType)) { return response.getOutputStream(); }//从HttpServletResponse中获取Writer对象 else if (Writer.class.isAssignableFrom(paramType)) { return response.getWriter(); } else { // should not happen Method method = parameter.getMethod(); throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method); } }这个参数的解析过程和ServletRequestMethodArgumentResolver中对象参数的解析过程如出一辙。我们对HttpServletRequest和HttpServletResponse参数的解析就先到这里了。