首先,我们都知道在使用spring框架的时候,无论是springmvc还是springboot,都可以在Controller层使用一些参数来取得我们想要的目的。
首先我们debug,进入最核心的方法中,发现核心方法就是ServletInvocableHandlerMethod类中的invokeAndHandle方法。
1 2 3
| 方法入口和结束的地方就是ServletInvocableHandlerMethod.invokeAndHandle()方法中 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; }
mavContainer.setRequestHandled(false); try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
重点看invokeForRequest: 调用Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
核心代码:InvocableHandlerMethod.getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(parameter, getBean().getClass()); args[i] = resolveProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (this.argumentResolvers.supportsParameter(parameter)) { try {
args[i] = this.argumentResolvers.resolveArgument( parameter, mavContainer, request, this.dataBinderFactory); continue; } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex); } throw ex; } } if (args[i] == null) { String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i); throw new IllegalStateException(msg); } } return args; }
|
####调用HandlerMethodArgumentResolverComposite.resolveArgument()
1 2 3 4 5 6 7 8 9 10
| @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); if (resolver == null) { throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]"); } return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory); }
|
####然后调用resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);根据不同的resolver对象返回不同的值。这就是spring的抉择。应该算是状态模式吧。
那我们看看每次返回的具体子类是什么:
// Reader的方法参数的实现类是@ServletRequestMethodArgumentResolver
// @RequestBody注解的实现是@RequestResponseBodyMethodProcessor
// Map参数的实现类是@HandlerMethodArgumentResolverComposite
然后他们调用各自的resolveArgument(parameter, mavContainer, webRequest, binderFactory)方法
去实现自己的逻辑去解析。从而返回不同的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { 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; }
|
#####下面的方法返回了Reader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Class<?> paramType = parameter.getParameterType(); if (WebRequest.class.isAssignableFrom(paramType)) { return webRequest; }
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); 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)) { return request.getSession(); } else if (HttpMethod.class == paramType) { return ((ServletWebRequest) webRequest).getHttpMethod(); } else if (Principal.class.isAssignableFrom(paramType)) { return request.getUserPrincipal(); } else if (Locale.class == paramType) { return RequestContextUtils.getLocale(request); } else if (TimeZone.class == paramType) { TimeZone timeZone = RequestContextUtils.getTimeZone(request); return (timeZone != null ? timeZone : TimeZone.getDefault()); } else if ("java.time.ZoneId".equals(paramType.getName())) { return ZoneIdResolver.resolveZoneId(request); } else if (InputStream.class.isAssignableFrom(paramType)) { return request.getInputStream(); } else if (Reader.class.isAssignableFrom(paramType)) {
return request.getReader(); } else { throw new UnsupportedOperationException( "Unknown parameter type: " + paramType + " in method: " + parameter.getMethod()); } }
|
######此方法返回了Json对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return adaptArgumentIfNecessary(arg, parameter); }
我们重写了解析了json的类,重写了240行的代码,方便我们解析参数 package org.springframework.http.converter.json;
@Override public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass); return readJavaType(javaType, inputMessage); }
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) { try { if (inputMessage instanceof MappingJacksonInputMessage) { Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView(); if (deserializationView != null) { return this.objectMapper.readerWithView(deserializationView).forType(javaType). readValue(inputMessage.getBody()); } }
InputStream inputStream = inputMessage.getBody(); String body = FileCopyUtils.copyToString(new InputStreamReader(inputStream,"UTF-8")); body = mxr(body); return this.objectMapper.readValue(body, javaType); } catch (IOException ex) { throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex); } }
|
这篇文章以代码居多,通过对spring如何修改参数的设置,我们可以在他的逻辑里定义自己想要的逻辑,比如修改参数。