执行目标方法InvocableHandlerMethod#invokeForRequest原理(最终参数解析,执行目标方法)

org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest(NativeWebRequest request,mavContainer,Object... providedArgs) {
	// 解析参数
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);{
		// 获取当前HandlerMethod的方法参数的信息
		MethodParameter[] parameters = getMethodParameters();
		// 没有参数
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}
		// 定义参数数组
		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			// 设置参数名称解析器,获取用户写的参数名称
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			// 先找在这之前是不是已经提供了执行参数,只有在异常处理的时候,会将异常信息参数传递过来
			// 正常请求的这个HandlerMethod的逻辑这个参数是为空的providedArgs
			// 还有@InitBinder注解中也会传递一个参数,叫WebDataBinder对象
			// 如果提供了参数,当当前方法需要相同类型的参数,就会直接赋值
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			// 拿到所有的参数解析器,看一下有哪些可以支持解析这个参数
			// 如果都解析不了,那么就抛出异常
			if (!this.resolvers.supportsParameter(parameter){
				return getArgumentResolver(parameter) != null;{
					// 解析过当前参数就需要缓存一下,省的每次都去找参数解析器
					HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
					// 没有缓存就遍历所有的参数解析器,在初始化的时候就已经设置了默认的一些参数解析器
					if (result == null) {
						for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
							// 判断是否支持
							if (resolver.supportsParameter(parameter)) {
								// 如果支持,就缓存起来,返回结果
								result = resolver;
								this.argumentResolverCache.put(parameter, result);
								break;
							}
						}
					}
					return result;
				}
			}) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
				// 开始调用所有的参数解析器解析参数
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);{
					// 获取参数解析器,因为上面调用supportsParameter是否支持的时候已经调用了getArgumentResolver缓存过了,parameter作为key,value就是参数解析器
					HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
					// 没有找到就是没有调用supportsParameter方法
					if (resolver == null) {
						throw new IllegalArgumentException("supportsParameter should be called first.");
					}
					// 使用找到的参数解析器开始解析参数
					// 不同参数解析的逻辑不一样
					// 1. 讲解PathVariable
					// PathVariableMethodArgumentResolver
					return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);{
						// 获取参数的名称信息,将PathVariable注解信息封装成NamedValueInfo,并进行缓存,防止每次解析都创建
						NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
						// 获取参数类型,支持参数为Optional包裹的参数
						MethodParameter nestedParameter = parameter.nestedIfOptional();
						// 解析嵌入值和表达式,例如: ${aa.bb},#{aa.bb}},如果没有表达式,就会原样返回
						Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name);
						// 根据参数名解析参数值
						Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);{
							// 在getHandler的时候,就已经对路径进行了解析,将路径变量保存到了request域中
							Map<String, String> uriTemplateVars = (Map<String, String>) request.getAttribute(
							HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
							// 获取参数值
							return (uriTemplateVars != null ? uriTemplateVars.get(name) : null);
						}
						// 如果没有解析到值
						if (arg == null) {
							// 使用默认值再来试一次
							if (namedValueInfo.defaultValue != null) {
								// 解析嵌入值和表达式,例如: ${aa.bb},#{aa.bb},如果没有表达式,就会原样返回
								arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
							}
							// 如果参数值必须,并且也不是Optional包裹的,说明解析不到值
							else if (namedValueInfo.required && !nestedParameter.isOptional()) {
								// 值缺失处理,该抛异常抛异常,该赋空对象赋空对象,自己处理
								handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
							}
							// 处理空值情况,布尔类型返回给false,基本类型抛异常,其他的原样返回
							arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
						}
						// 参数值为"",且有默认值,解析嵌入值和表达式,例如: ${aa.bb},#{aa.bb}},如果没有表达式,就会原样返回
						else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
							arg = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);
						}
						// 判断binderFactory是否为空,发起请求之前,都创建过这个对象,所以不为空
						// 用于参数的绑定
						if (binderFactory != null) {
							// 创建WebBinder对象
							WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);{
								// 创建WebDataBinder实例
								WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);{
									return new ExtendedServletRequestDataBinder(target, objectName);
								}
								// 当前工厂中的WebBindingInitializer是否为空
								// 在创建binderFactory的时候,就已经将initializer设置进来了
								// return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
								// 而getWebBindingInitializer是在添加了@EnableMVC加入RequestMappingAdapter初始化的时候,设置进来的
								// 如果是默认的RequestMappingAdapter就没有
								// 类型为org.springframework.web.bind.support.ConfigurableWebBindingInitializer
								if (this.initializer != null) {
									this.initializer.initBinder(dataBinder, webRequest);{
										// 初始化Binder,设置一些属性,参数校验器,类型转换起,异常绑定处理器,属性编辑器
										binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
										if (this.directFieldAccess) {binder.initDirectFieldAccess();}
										if (this.messageCodesResolver != null) {binder.setMessageCodesResolver(this.messageCodesResolver);}
										if (this.bindingErrorProcessor != null) {binder.setBindingErrorProcessor(this.bindingErrorProcessor);}
										if (this.validator != null && binder.getTarget() != null && this.validator.supports(binder.getTarget().getClass())) {
											binder.setValidator(this.validator);
										}
										if (this.conversionService != null) { binder.setConversionService(this.conversionService);}
										if (this.propertyEditorRegistrars != null) {
											for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
												propertyEditorRegistrar.registerCustomEditors(binder);
											}
										}
									}
								}
								// 这是工厂自身提供的初始化方法
								initBinder(dataBinder, webRequest);{
									// 遍历所有的InitBinder方法,前面已经找出来了,是Controller自身的和@ControllerAdvice中全局的一起
									for (InvocableHandlerMethod binderMethod : this.binderMethods) {
										// 判断当前InitBinderMethod是否可用,除非在InitBinder设置了参数
										if (isBinderMethodApplicable(binderMethod, dataBinder)) {
											// 根据参数执行方法,上面已经详细讲过了
											Object returnValue = binderMethod.invokeForRequest(request, null, dataBinder);
											// 返回值必须是void
											if (returnValue != null) {
												throw new IllegalStateException("@InitBinder methods must not return a value (should be void): " + binderMethod);
											}
										}
									}
								}
								return dataBinder;
							}
							// 创建好了WebDataBinder之后,对参数进行转换
							// 对参数进行适配,利用Spring自身提供的类型转换机制来就参数进行类型转换
							// 也可以@InitBinder获取的WebDataBinder对象,设置一个相关的转换器来处理Spring没有提供的默认的转换器
							// 例如:将String->枚举,Spring可能就没有提供,自己就可以自定义转换器,设置到WebDataBinder binder中
							// 这样就能就String转换为枚举类型
							arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
							// 参数类型转换之后,还是没有获取到值的情况
							if (arg == null && namedValueInfo.defaultValue == null && namedValueInfo.required && !nestedParameter.isOptional()) {
								handleMissingValueAfterConversion(namedValueInfo.name, nestedParameter, webRequest);
							}
						}
						// 处理结果后的参数值
						handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);{
							String key = View.PATH_VARIABLES;
							int scope = RequestAttributes.SCOPE_REQUEST;
							Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(key, scope);
							if (pathVars == null) {
								pathVars = new HashMap<>();
								// 将数据保存到请求域中
								request.setAttribute(key, pathVars, scope);
							}
							// 因为可能存在多个路径变量,所以需要使用map
							pathVars.put(name, arg);
						}
						return arg;
					}
					// 2. 讲解ReqeustBody
					// resolver = RequestResponseBodyMethodProcessor
					return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);{
						// 获取到请求参数对象,使用消息转换器读取消息
						Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());{
							Object arg = readWithMessageConverters(inputMessage, parameter, paramType);{
								boolean noContentType = false;
								MediaType contentType = inputMessage.getHeaders().getContentType();
								// 给默认的内容类型
								if (contentType == null) {
									noContentType = true;
									contentType = MediaType.APPLICATION_OCTET_STREAM;
								}
								// 获取到参数对象所属的类
								Class<?> contextClass = parameter.getContainingClass();
								// 获取参数的类型,如果给定的参数类型不是Class,返回null
								Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
								// 如果参数类型不是Class
								if (targetClass == null) {
									// 根据给的参数找到对应类的Class来
									ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
									targetClass = (Class<T>) resolvableType.resolve();
								}
								// 判断输入消息的类型是不是HttpRequest,标注了@RequestBody的情况是ServletServerHttpRequest,符合条件
								// 获取到请求类型 POST转HttpMethod对象
								HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
								// 读取的值默认为空对象
								Object body = NO_VALUE;
								try {
								    // 根据传递过来的inputMessage消息提创建一个EmptyBodyCheckingHttpInputMessage,内部会自己处理请求体
									//比如自己设置了inputMessage
									EmptyBodyCheckingHttpInputMessage message = new EmptyBodyCheckingHttpInputMessage(inputMessage);{
										this.headers = inputMessage.getHeaders();
										// 获取body
										InputStream inputStream = inputMessage.getBody();
										// 默认就是为false,除非传递的inputMessage参数重写了markSupported为true
										if (inputStream.markSupported()) {
											inputStream.mark(1);
											this.body = (inputStream.read() != -1 ? inputStream : null);
											inputStream.reset();
										}
										else {
											// 创建一个新的输入流
											PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
											// 将请求体的输入村进入
											int b = pushbackInputStream.read();
											if (b == -1) {
												this.body = null;
											}
											else {
												this.body = pushbackInputStream;
												pushbackInputStream.unread(b);
											}
										}
									}
									// 遍历所有的消息类型转换器对消息进行类型转换
									// 这里的消息转换器有三种情况,详见消息转换器HttpMessageConverter原理
									for (HttpMessageConverter<?> converter : this.messageConverters) {
										// 获取消息转换器的类型
										Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
										// 判断消息转换器是否是GenericHttpMessageConverter,如果不是,返回null,是的话就强转为GenericHttpMessageConverter类型
										GenericHttpMessageConverter<?> genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
										// 判断当前消息转换器是否可以读取请求数据
										if (genericConverter != null ?
												// 如果消息类型为GenericHttpMessageConverter,那么直接判断它是否可以读取
												genericConverter.canRead(targetType, contextClass, contentType){
													// 判断消息转换器是否支持媒体类型
													if (!canRead(mediaType)) {
														return false;
													}
													// 将参数类型包装成JavaType类型
													JavaType javaType = getJavaType(type, contextClass);
													// 获取到合适的ObjectMapper,这个ObjectMapper就是有来序列化的
													ObjectMapper objectMapper = selectObjectMapper(javaType.getRawClass(), mediaType);{
														// objectMapperRegistrations默认为空,除非自己设置的
														if (targetMediaType == null || CollectionUtils.isEmpty(this.objectMapperRegistrations)) {
															return this.defaultObjectMapper;
														}
														// 如果注册表不为空
														// 遍历ObjectMapperRegistration注册表,根据媒体类型来获取对应的ObjectMapper
														for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> typeEntry : getObjectMapperRegistrations().entrySet()) {
															if (typeEntry.getKey().isAssignableFrom(targetType)) {
																for (Map.Entry<MediaType, ObjectMapper> objectMapperEntry : typeEntry.getValue().entrySet()) {
																	if (objectMapperEntry.getKey().includes(targetMediaType)) {
																		return objectMapperEntry.getValue();
																	}
																}
																return null;
															}
														}
														// 都没找到,返回默认的
														return this.defaultObjectMapper;
													}
													// 如果没有找到objectMapper,就没有办法序列化
													if (objectMapper == null) {
														return false;
													}
													// 判断objectMapper是否可以序列化javaType类型
													AtomicReference<Throwable> causeRef = new AtomicReference<>();
													if (objectMapper.canDeserialize(javaType, causeRef)) {
														return true;
													}
													return false;
												} :
												// 否则还要判断参数类型不能为空,再判断它是否可以读取
												(targetClass != null && converter.canRead(targetClass, contentType))) {
											// 实现了RequestResponseBodyAdvice的执行链,在创建当前参数解析器的时候就已经将
											// 在RequestMappingHandlerAdapter初始化的时候,给参数解析器设置的
											// this.requestResponseBodyAdvice就是在RequestMappingHandlerAdapter初始化的时候,执行initControllerAdviceCache();方法
											// 从@ControllerAdvice中,实现了requestResponseBodyAdvice的类缓存下来了
											// resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
											RequestResponseBodyAdviceChain advice = this.advice;
											// 上面已经将请求体的数据存在EmptyBodyCheckingHttpInputMessage massage中了
											if (message.hasBody()) {
												// 找到真实要用的HttpInputMessage消息体
												// 因为HttpInputMessage可以通过ControllerAdviceBean中实现RequestBodyAdvice来处理,返回新的HttpInputMessage
												HttpInputMessage msgToUse = advice.beforeBodyRead(message, parameter, targetType, converterType);{
													// 找到匹配的可用的RequestBodyAdvice,因为可能在@ControllerAdvice中设置条件,可能不满足当前Bean的方法
													for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {
														// 判断当前RequestBodyAdvice的supports是否返回的true
														if (advice.supports(parameter, targetType, converterType)) {
															// 调用接口的beforeBodyRead,在这之前还没开始读取,所以可以改请求体内部的数据
															request = advice.beforeBodyRead(request, parameter, targetType, converterType);{
																// 我自定义的RequestBodyAdvice,获取body,改变数据,然后又存进去,可达到加密解密的
																InputStream body = inputMessage.getBody();
																Object object = JSON.parseObject(IoUtil.read(body, Charset.defaultCharset()), targetType);
																if (object instanceof A) {
																	((A) object).setId(-1)
																}
																// 将数据返回出去
																return new MappingJacksonInputMessage(new ByteArrayInputStream(JSON.toJSONString(object).getBytes(StandardCharsets.UTF_8)), inputMessage.getHeaders());
															}
														}
													}
													return request;
												}
												// 调用转换器的read方法
												body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
														((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));{
															// 将Bean和参数类型封装成JavaType
															// 再使用ObjectMapper读取body
															JavaType javaType = getJavaType(type, contextClass);
															return readJavaType(javaType, inputMessage);
														}
												// 上面调用过RequestBodyAdvice的beforeRead方法,现在调用RequestBodyAdvice的advice.afterBodyRead
												// 就是一些读取前后的切面
												body = advice.afterBodyRead(body, msgToUse, parameter, targetType, converterType);
											}
											else {
												// 如果没有请求体
												// 上面调用过RequestBodyAdvice的beforeRead,afterRead方法,在这里调用RequestBodyAdvice的advice.handleEmptyBody
												// 处理请求体为空的数据
												body = advice.handleEmptyBody(null, message, parameter, targetType, converterType);
											}
											break;
										}
									}
								}
								catch (IOException ex) {
									throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
								}
								// 如果body为初始值NO_VALUE,表示没有消息处理器或者没有合适的消息处理器来处理当前参数
								if (body == NO_VALUE) {
									// 没有请求方法POST,或者请求方法不支持,或者没有请求体,这个时候没有内容是正常的,直接返回null
									if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) {
										return null;
									}
									// 否则还没解析出参数表示无法处理当前这个请求参数
									throw new HttpMediaTypeNotSupportedException(contentType,getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));

								}
								// 返回处理后的请求体
								return body;
							}
							// 没有读取到参数,但是参数又是必须要的,设置了required=true
							if (arg == null && checkRequired(parameter)) {
								// 参数不可读的异常
								throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage);
							}
							// 返回解析之后的参数
							return arg;
						}
						// 获取在方法参数写的名称
						String name = Conventions.getVariableNameForParameter(parameter);
						// 判断binderFactory是否为空,发起请求之前,都创建过这个对象,所以不为空
						if (binderFactory != null) {
							// 创建Binder实例,在讲解PathVariable的时候代码解释过了
							WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
							if (arg != null) {
								// 校验参数,如果有必要就是@NotEmpty等等这种参数
								validateIfApplicable(binder, parameter);{
									// 找到方法中所有的参数注解,来校验
									Annotation[] annotations = parameter.getParameterAnnotations();
									for (Annotation ann : annotations) {
										// 调用校验工具类校验
										Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);{
											// 获取注解类型
											Class<? extends Annotation> annotationType = ann.annotationType();
											// 获取注解全类名称
											String annotationName = annotationType.getName();
											// 如果加了@javax.validation.Valid这个注解
											if ("javax.validation.Valid".equals(annotationName)) {
												// 直接返回固定数组
												return EMPTY_OBJECT_ARRAY;
											}
											// 获取@Validated注解信息
											Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
											if (validatedAnn != null) {
												// 获取校验的分组信息
												Object hints = validatedAnn.value();
												// 转换成数组,因为可能填写的是一个class,要包装成数组形成
												return convertValidationHints(hints);{
													// 如果没有校验分组,直接返回固定数组
													if (hints == null) {
														return EMPTY_OBJECT_ARRAY;
													}
													// 返回指定的分组
													return (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
												}
											}
											// 其他情况,如果注解为Valid开头,反射获取分组名
											if (annotationType.getSimpleName().startsWith("Valid")) {
												// 和Validated差不多
												Object hints = AnnotationUtils.getValue(ann);
												return convertValidationHints(hints);
											}
											// 如果都不是,和@Valid没关系,那就返回null
											return null;
										}
										// 如果上面找校验分组找到了,那就
										if (validationHints != null) {
											// 按照分组,使用DataBinder开始校验
											binder.validate(validationHints);{
												// 获取要校验的目标对象
												Object target = getTarget();
												// 获取在binder中创建的BindingResult获取出来,用来存储校验失败的结果
												BindingResult bindingResult = getBindingResult();
												// 	private final List<Validator> validators = new ArrayList<>();
												// 获取所有的校验器对参数一一校验
												for (Validator validator : getValidators()) {
													// 存在校验分组,并且为智能类型SmartValidator,调用SmartValidator的方法
													if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
														((SmartValidator) validator).validate(target, bindingResult, validationHints);{
															if (this.targetValidator != null) {
																// 调用目标校验器对参数进行校验,返回Set<ConstraintViolation<Object>> violations
																// ConstraintViolation一个描述单个约束失败的类,验证一个对象将会返回ConstraintViolation的集合
																processConstraintViolations(this.targetValidator.validate(target), errors);{
																	// 遍历所有的错误消息
																	for (ConstraintViolation<Object> violation : violations) {
																		// 获取错误的字段
																		String field = determineField(violation);
																		// 获取字段的错误信息
																		FieldError fieldError = errors.getFieldError(field);
																		if (fieldError == null || !fieldError.isBindingFailure()) {
																			ConstraintDescriptor<?> cd = violation.getConstraintDescriptor();
																			String errorCode = determineErrorCode(cd);
																			Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, cd);
																			//  判断错误类型是不是BindingResult,如果是,将错误结果放入BindingResult中
																			// 因为BindingResult也是一个Errors类型
																			if (errors instanceof BindingResult) {
																				BindingResult bindingResult = (BindingResult) errors;
																				String nestedField = bindingResult.getNestedPath() + field;
																				// 嵌套字段是否为空
																				if (nestedField.isEmpty()) {
																					String[] errorCodes = bindingResult.resolveMessageCodes(errorCode);
																					ObjectError error = new ViolationObjectError(errors.getObjectName(), errorCodes, errorArgs, violation, this);
																					bindingResult.addError(error);
																				}
																				// 非嵌套字段
																				else {
																					Object rejectedValue = getRejectedValue(field, violation, bindingResult);
																					String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field);
																					FieldError error = new ViolationFieldError(errors.getObjectName(), nestedField,rejectedValue, errorCodes, errorArgs, violation, this);
																					bindingResult.addError(error);
																				}
																			}
																			else {
																				// 将数据添加到errors中
																				errors.rejectValue(field, errorCode, errorArgs, violation.getMessage());
																			}
																		}
																	}
																}
														}
													}
													// 其他情况直接调用校验方法
													else if (validator != null) {
														validator.validate(target, bindingResult);
													}
												}
											}
											break;
										}
									}
								}
								// 上面校验的结果已经存在BindingResult中了,如果存在错误,
								if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter){
																				// 获取参数的索引
																				int i = parameter.getParameterIndex();
																				// 获取参数类型
																				Class<?>[] paramTypes = parameter.getExecutable().getParameterTypes();
																				// 如果被校验的参数紧接着的下一个参数不是Errors(BindingResult)对象,
																				boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
																				// 上面条件为true表示下一个参数是BindingResult
																				// !hasBindingResult表示校验的参数之后紧挨的不是BindingResult
																				return !hasBindingResult;
																			}) {
									// 表示校验出错,并且校验的参数紧挨着的对象没有用BindingResult接受错误信息,就抛出异常
									throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
								}
							}
							// 将BindingResult的数据存入mavContainer的属性中,哪怕是没有错误,也会根据这个固定的key存入
							// 	String MODEL_KEY_PREFIX = BindingResult.class.getName() + ".";
							if (mavContainer != null) {
								mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
							}
						}
						// 看一下参数是否需要适配并返回
						// 如果参数是Optional,我们处理参数之后,也要包装为Optional还给用户
						// 如果不是,就原样返回
						return adaptArgumentIfNecessary(arg, parameter);
					}
					// 3. 讲解RequestParam,和1. PathVariable逻辑一样,相同的父类,以下逻辑不同,是抽象的
					// 不光会处理普通参数,还会处理文件类型参数
					// RequestParamMethodArgumentResolver
					return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);{
						// 根据参数名解析参数值
						Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);{
							// 获取原生的HttpServletRequest对象
							HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
							if (servletRequest != null) {
								// 解析文件参数,先看一下是不是文件
								Object mpArg = MultipartResolutionDelegate.resolveMultipartArgument(name, parameter, servletRequest);{
									// 在请求的时候,如果是文件请求,这个对象已经被包装过了
									MultipartHttpServletRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
									// 判断是否是文件请求的依据有两个,一个是之前校验的请求对象封装成了MultipartHttpServletRequest
									// 另一个是根据contentType.toLowerCase().startsWith("multipart/"));
									boolean isMultipart = (multipartRequest != null || isMultipartContent(request));
									// 获取参数类型,List<MultipartFile>,MultipartFile[]逻辑一样,增加了类型判断,这里省去了重复代码
									if (MultipartFile.class == parameter.getNestedParameterType()) {
										// 如果你不是文件类型的请求,那么你用这个参数也没有用
										if (!isMultipart) {
											return null;
										}
										// 之前没有将HttpServletRequest包装过包装一下
										if (multipartRequest == null) {
											multipartRequest = new StandardMultipartHttpServletRequest(request);
										}
										// 通过封装的请求对象获取文件对象
										// 根据不同的文件解析器创建文件对象的方式不一样
										// 在请求进来的时候,文件已经被解析过程,multipartResolver解析之后,将文件给MultipartHttpServletRequest对象了
										// 也就是multipartRequest对象
										return multipartRequest.getFile(name);{
											// 从请求对象中获取文件流数据
											Collection<Part> parts = request.getParts();
											this.multipartParameterNames = new LinkedHashSet<>(parts.size());
											// 每一个文件就是一个Part
											for (Part part : parts) {
												// 解析请求头
												String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);
												ContentDisposition disposition = ContentDisposition.parse(headerValue);
												// 获取文件名
												String filename = disposition.getFilename();
												if (filename != null) {
													// 创建StandardMultipartFile对象
													files.add(part.getName(), new StandardMultipartFile(part, filename));
												}
											}
											// 保存解析到的所有文件对象
											setMultipartFiles(files);
										}
									}
									// 如果文件类型直接为Part,数组,集合
									else if (Part.class == parameter.getNestedParameterType()) {
										if (!isMultipart) {
											return null;
										}
										// 直接从request对象中就能获取
										// 如果是数组,或者集合,就要通过request.getParts();再进行遍历包装返回
										return request.getPart(name);
									}
									// 没有解析到文件
									else {
										return UNRESOLVABLE;
									}
								}
								// 没有解析到文件
								if (mpArg != MultipartResolutionDelegate.UNRESOLVABLE) {
									return mpArg;
								}
							}
							Object arg = null;
							MultipartRequest multipartRequest = request.getNativeRequest(MultipartRequest.class);
							// 获取文件参数
							if (multipartRequest != null) {
								List<MultipartFile> files = multipartRequest.getFiles(name);
								if (!files.isEmpty()) {
									Object arg = (files.size() == 1 ? files.get(0) : files);
								}
							}
							// 获取普通参数
							if (arg == null) {
								String[] paramValues = request.getParameterValues(name);
								ifObject (paramValues != null) {
									arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
								}
							}
							return arg;
						}

					}
					// 4. 讲解没有注解
					// 使用的实ServletModelAttributeMethodProcessor,它是在Apdate中添加的兜底的处理器
					return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);{
						// 获取参数名
						String name = ModelFactory.getNameForParameter(parameter);
						// 获取是否存在ModelAttribute注解
						ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
						// 如果不为空,保存注解的binding信息
						if (ann != null) {
							// 表示当前参数需要被绑定,需要存到model中
							mavContainer.setBinding(name, ann.binding());
						}
						Object attribute = null;
						BindingResult bindingResult = null;
						// 如果mavContainer已经存在这个属性
						if (mavContainer.containsAttribute(name)) {
							// 直接从Model获取值
							attribute = mavContainer.getModel().get(name);
						}
						else {
							try {
							    // 创建参数实例对象,找默认的构造方法进行实例化参数对象
								// 在创建对象的过程中也会去参数进行校验等等
								attribute = createAttribute(name, parameter, binderFactory, webRequest);{
									// 从请求中获取数据,request.getParam
									String value = getRequestValueForAttribute(attributeName, request);
									if (value != null) {
										// 通过获取到的值进行类型转换成目标值
										Object attribute = createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request);{
											// 创建Binder实例
											DataBinder binder = binderFactory.createBinder(request, null, attributeName);
											// 创建类型转换类,Spring专门提供类型转换的类
											ConversionService conversionService = binder.getConversionService();
											if (conversionService != null) {
												// 接收的数据类型(req获取的都是String)
												TypeDescriptor source = TypeDescriptor.valueOf(String.class);
												// 需要转换的目标类型(参数类型)
												TypeDescriptor target = new TypeDescriptor(parameter);
												// 判断是否可以进行转换
												// 如果可以转换将数据类型以及目标类型封装成CacheKey,转换器作为值缓存起来,不需要每次都找
												// 无参构造找不到对应的转换器,只有有参构造才能找到对应的Convert
												// 对于无参构造,都是调用下面的super.createAttribute,来创建空参数的对象,所以无需进行转换
												if (conversionService.canConvert(source, target)) {
													// 调用binder的转换方法,上面已经讲过了
													/ 对参数进行适配,利用Spring自身提供的类型转换机制来就参数进行类型转换
													// 也可以@InitBinder获取的WebDataBinder对象,设置一个相关的转换器来处理Spring没有提供的默认的转换器
													// 例如:将String->枚举,Spring可能就没有提供,自己就可以自定义转换器,设置到WebDataBinder binder中
													// 这样就能就String转换为枚举类型
													return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
												}
											}
											return null;
										}
										// 如果转换成了目标对象,就直接返回
										if (attribute != null) {
											return attribute;
										}
									}
									// 没有转换成功,也就是上面Spring没有提供对应的类型转换器,这里就对类型进行通用处理,来创建参数对象
									return super.createAttribute(attributeName, parameter, binderFactory, request);{
										// 获取参数类型
										MethodParameter nestedParameter = parameter.nestedIfOptional();
										Class<?> clazz = nestedParameter.getNestedParameterType();
										// 获取参数类型的构造方法,如果有无参构造方法,优先选择无参构造
										Constructor<?> ctor = BeanUtils.getResolvableConstructor(clazz);
										// 通过构造方法创建对象
										// 如果有默认构造方法,直接使用默认的构造方法
										// 如果不是默认构造方法,从request获取对应的值来创建实例对象
										Object attribute = constructAttribute(ctor, attributeName, parameter, binderFactory, webRequest);
										if (parameter != nestedParameter) {
											attribute = Optional.of(attribute);
										}
										return attribute;
									}
								}
							}
							// 发生异常
							catch (BindException ex) {
								// 如果发生BindException异常了,判断是否有BindingResult接收,如果没有,抛出异常
								if (isBindExceptionRequired(parameter)) {
									throw ex;
								}
								// 其他情况,存在BindingResult接收异常信息,该怎么返回怎么返回,错误结果已经绑定到BindingResult中了
								if (parameter.getParameterType() == Optional.class) {
									attribute = Optional.empty();
								}
								else {
									attribute = ex.getTarget();
								}
								bindingResult = ex.getBindingResult();
							}
						}
						// 如果没有异常,正常创建了参数对象
						if (bindingResult == null) {
							// 创建Binder实例,通过Binder来对参数进行校验
							WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
							if (binder.getTarget() != null) {
								// 如果ModelAttribute设置了binding=false(默认为true),表示当前ModelAttribute标注的参数不能被绑定数据
								if (!mavContainer.isBindingDisabled(name)) {
									// 将请求参数的值一一绑定到参数中
									bindRequestParameters(binder, webRequest);
								}
								// 对参数进行校验,如果有异常,会绑定到BindingResult中
								validateIfApplicable(binder, parameter);
								if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
									throw new BindException(binder.getBindingResult());
								}
							}
							// 创建好了WebDataBinder之后,对参数进行转换,如果有必要的话
							// 这个就是利用Spring自身提供的类型转换机制来就参数进行类型转换
							if (!parameter.getParameterType().isInstance(attribute)) {
								// 对参数进行适配,利用Spring自身提供的类型转换机制来就参数进行类型转换
								// 也可以@InitBinder获取的WebDataBinder对象,设置一个相关的转换器来处理Spring没有提供的默认的转换器
								// 例如:将String->枚举,Spring可能就没有提供,自己就可以自定义转换器,设置到WebDataBinder binder中
								// 这样就能就String转换为枚举类型
								attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
							}
							// 获取BindingResult
							bindingResult = binder.getBindingResult();
						}

						// 同步Model数据,将bindingResult的Model数据同步到mavContainer中
						Map<String, Object> bindingResultModel = bindingResult.getModel();{
							// 默认就将当前参数的实例对象和BindingResult存入到Model中了
							Map<String, Object> model = new LinkedHashMap<>(2);
							model.put(getObjectName(), getTarget());
							model.put(MODEL_KEY_PREFIX + getObjectName(), this);
							return model;
						}
						// 同步Model数据,将bindingResult的Model数据同步到mavContainer中
						mavContainer.removeAttributes(bindingResultModel);
						mavContainer.addAllAttributes(bindingResultModel);
						// 返回处理好的参数
						return attribute;
					}
				}
			}
			catch (Exception ex) {
				throw ex;
			}
		}
		return args;
	}
	// 反射执行
	return doInvoke(args);
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值